# 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}]] – Pinguin Dirk Oct 17 '13 at 17:05
• @PinguinDirk. Fo shizzle :) – RunnyKine Oct 17 '13 at 17:09
• I do not want random numbers of items. I want specific numbers of each item in the multiset. – Tyler Durden Oct 17 '13 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. – RunnyKine Oct 17 '13 at 18:33
• @TylerDurden. See my update. – RunnyKine Oct 17 '13 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. – Tyler Durden Oct 17 '13 at 18:12
• @TylerDurden So you've got it. – Artes Oct 17 '13 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} :-) – Mr.Wizard Dec 29 '13 at 20:08
• @Mr.Wizard Pfft lame... 1 ~Range~ 9 ~ConstantArray~ 3 ~Flatten~ (2 ~List~ 1) :P – rm -rf Dec 29 '13 at 20:59
• reductio ad absurdum – Mr.Wizard Dec 29 '13 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. – Tyler Durden Oct 17 '13 at 18:14
• @TylerDurden ok :) see my edit – Kuba Oct 17 '13 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. – Tyler Durden Oct 29 '13 at 16:45
• +1 for the first one; a nice way to use only two functions! – Mr.Wizard Dec 29 '13 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. – Artes Dec 29 '13 at 22:33
• Oh sorry - for some reason I imagined the sequence began with zeros. I'll modify my answer. – Aky Dec 29 '13 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? – Artes Dec 29 '13 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 Dec 30 '13 at 5:59