# Concise way to generate multiset lists

I wrote the following to generate a multiset with the same number of items over a fixed range:

ConstantArray[#, 3]& /@ Range[9] // Flatten

{1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9}


This approach uses four named functions (Range, Flatten, ConstantArray and Map (/@)) and one pure function (ending with &).
Is there a way to do the same thing with fewer functions?

Also, if I wanted to have variable numbers of items in my multiset how would I do that?
For example, let's say I wanted a multiset like { 1, 1, 1, 1, 2, 2, 3, 4, 4, 4, 6, 6, 7, 8, 8, 8 }.

By a "variable number of items" I do not mean random, I mean a specified variable number.

   f[n_, k_] := Table[ConstantArray[i, n], {i, k}]


Now you can vary the number of items of each:

f[3, 9] // Flatten


{1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9}

f[4, 10] // Flatten


{1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10}

for random Situation:

fRandom[n_, k_] := Table[ConstantArray[i, RandomInteger[{1, n}]], {i, k}]


For your second situation try this;

Inner[ConstantArray, Range[8], {4, 2, 1, 3, 0, 2, 1, 3}, List] // Flatten


{1, 1, 1, 1, 2, 2, 3, 4, 4, 4, 6, 6, 7, 8, 8, 8}

• for constant k, one could also do: Flatten[Table[i, {i, 10}, {j, 3}]] Commented Oct 17, 2013 at 17:05
• @PinguinDirk. Fo shizzle :) Commented Oct 17, 2013 at 17:09
• I do not want random numbers of items. I want specific numbers of each item in the multiset. Commented Oct 17, 2013 at 18:11
• @TylerDurden, Well, initially you did not specify this. How exactly do you want to specify those numbers, you need to be more specific so we know what you want. Commented Oct 17, 2013 at 18:33
• @TylerDurden. See my update. Commented Oct 17, 2013 at 19:32

These should be the most efficient and tersest

Ceiling[ Range @ 27 / 3 ]


or

Array[ Ceiling[#/3] &, 27]


yield

{1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9}


they both can be tersely written in the Front End (see details of Ceiling) as:

or

For the second problem there are many approaches, here is a solution with a determined number of items ( Count[{1, 1, 1, 1, 2, 2, 3, 4, 4, 4, 6, 6, 7, 8, 8, 8}, #] & /@ Range[8]) as in your example:

Inner[ ConstantArray, Range @ 8, {4, 2, 1, 3, 0, 2, 1, 3}, Join]

{1, 1, 1, 1, 2, 2, 3, 4, 4, 4, 6, 6, 7, 8, 8, 8}


or

Flatten @ MapThread[ ConstantArray, {Range @ 8, {4, 2, 1, 3, 0, 2, 1, 3}}]

• I do not want random numbers of items. I want specific numbers of each item in the multiset. Commented Oct 17, 2013 at 18:12
• @TylerDurden So you've got it. Commented Oct 17, 2013 at 18:24

To me, the most straightforward way seems to be:

Flatten[ConstantArray[Range[9], 3], {2, 1}]
(* {1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9} *)


i.e., instead of repeating each element in the list 3 times, you repeat the entire list 3 times and flatten it using the appropriate second argument.

• +1 -- this is the same method I use, though usually with infix: Range@9 ~ConstantArray~ 3 ~Flatten~ {2, 1} :-) Commented Dec 29, 2013 at 20:08
• @Mr.Wizard Pfft lame... 1 ~Range~ 9 ~ConstantArray~ 3 ~Flatten~ (2 ~List~ 1) :P
– rm -rf
Commented Dec 29, 2013 at 20:59
• reductio ad absurdum Commented Dec 29, 2013 at 22:33

No Rules?, so this is one from Szabolc's site:

 Range[9] /. n_Integer :> Sequence[n, n, n]

{1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9}


Since you haven't described how those numbers should vary for second part, maybe something like:

Sort@RandomInteger[{1, 10}, 27]

{1, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 10}


Ok, let's say you have list of numbers which are referring to consecutive integers repetition:

Flatten@MapIndexed[ConstantArray[#2, #] &, {4, 3, 5, 1, 2, 3}]

{1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 5, 5, 6, 6, 6}


Or similar:

i = 0;
Flatten[ConstantArray[++i, #] & /@ {4, 3, 5, 1, 2, 3}]

{1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 5, 5, 6, 6, 6}

• I do not want random numbers of items. I want specific numbers of each item in the multiset. For example, in the case shown I want four 1's, two 2's, one 3, three 4's, no fives, two 6's, one 7, and three 8's. Commented Oct 17, 2013 at 18:14
• @TylerDurden ok :) see my edit
– Kuba
Commented Oct 17, 2013 at 19:35
Flatten[ Range[ 1, 9, {1, 1, 1}], {2, 1}]
Join @@ Table[ i, {i, 9}, {3}]
Join @@ Array[ # &, {9, 3}]
Table[ 1/9 (3 n - 2 Sqrt[3] Cos[(2 π n)/3 + π/6] + 3), {n, 27}]


{1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9}

• This answer gets the booby prize, or the tongue-in-cheek prize, as the case may be. Commented Oct 29, 2013 at 16:45
• +1 for the first one; a nice way to use only two functions! Commented Dec 29, 2013 at 20:11

MapThread[ConstantArray, {Range[9], RandomInteger[{1, 3}, 9]}] // Flatten
(* {1, 1, 1, 2, 2, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 9} *)


Yet another way, for the first part:

With[{n = 3, k = 10}, Quotient[Range[k n], n, -n+1]] (* incorporating Artes' suggestion *)


Updated:

For the second part, an approach not already covered in the other answers:

Module[{i = 1, reps = {4, 5, 1, 3}},
Fold[#1~Join~ConstantArray[ i++, #2] &, {}, reps]] (* reps are variable repetition factors *)


{1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4, 4, 4}

• Very nice (+1) however I'd rather do this Quotient[ Range[3 9], 3, -2] to get exaclty what has been expected. Consider to answer another question in the OP. Commented Dec 29, 2013 at 22:33
• Oh sorry - for some reason I imagined the sequence began with zeros. I'll modify my answer.
– Aky
Commented Dec 29, 2013 at 22:42
• Why do you need With? There is no need for Range[1, k n] since it's equal to Range[k n]. And what about variable number of items? Commented Dec 29, 2013 at 22:50
• Oops, that was a mistake - I was really sleepy when I wrote that. Fixed now. The With is just for convenience and generalization, if someone wants to use the same method with a different range or repetition value. (I could've written it as a function.)
– Aky
Commented Dec 30, 2013 at 5:59