How to replace every element in a list?

I have a list

s:={1, 2, 4, 7, 8}


and I wish to replace every element in the list with Range[Max[s]].

I know that I could replace every element individually using ReplaceAll by doing

Flatten[s /. {1 -> Range[Max[s]], 2 -> Range[Max[s]],
4 -> Range[Max[s]], 7 -> Range[Max[s]], 8 -> Range[Max[s]]}]


However, s is arbitrary, and I will be using this for lists much longer than s. I would like to be able to perform this with one command, rather than replacing each element individually.

I have tried

s /. s -> Range[Max[s]]


But this just returns the range once. I haven't been able to find anything about replacing every element of a list.

Is this acceptable?

s={1, 2, 4, 7, 8};
Flatten[Map[Range[Max[s]]&,s]]


which is the same as

Flatten[Range[Max[s]]&/@s]


and both produce

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


which matches what your example code produces.

Map or /@ will replace each item in the list with the result of a function applied to the item in the list. In your case the function doesn't depend on any individual item, but on the Max of the whole list. And the & turns Range[Max[s]] into a function. And the final enclosing Flatten gets rid of the nesting of the individual lists.

Does that help explain the thinking?

• Yes! Thank you! Commented Jun 17, 2020 at 7:38

Using Replace(All) or Map is kinda slow for larger lists. Why not simply use:

ConstantArray[Range[Max[s]], Length[s]]


With ReplaceAll you need a pattern to restrict the replacement or it will match the entire list:

Flatten[s /. _Integer -> Range[Max@s]]

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


Performance

SHuisman's answer reminded me of performance. If that is important consider PadRight:

PadRight[Range[1], #*Length[s], Range@#] &[Max@s]


Range[1] is used instead of {} as the seed for PadRight because it creates a packed array.

Benchmark:

Needs["GeneralUtilities"]

fn1[s_List] := Flatten @ ConstantArray[Range[Max[s]], Length[s]]

fn2[s_List] := PadRight[Range[1], #*Length[s], Range@#] &[Max@s]

BenchmarkPlot[{fn1, fn2}, RandomInteger[9, #] &]
BenchmarkPlot[{fn1, fn2}, RandomInteger[#, 1*^5] &]


• PadRight is surprisingly fast! Wow! Flatten@, Join@@ or Catenate@ btw have quite different timings. but your PadRight stays faster… Commented Jun 17, 2020 at 12:33
Mod[Range[Length[s] #], #, 1] & @ Max[s]

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

First @ ArrayReshape[Range @ #, {1, Length[s] #}, "Periodic"] & @ Max[s]

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

(* Not a one-liner, but easy enough to do so *)
s = {1, 2, 4, 7, 8};

l = Length[s];

item = Range[Max[s]]

Replace[s, {_ -> item}, {1}]  (* use level spec *)

(* Flatten if desired *)

• l = Length[s]; does not appear to be used? Also consider Cases[s, _ -> item] as Cases defaults to a levelspec of {1}`. Commented Jun 20, 2020 at 13:37