2
$\begingroup$

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.

$\endgroup$

5 Answers 5

4
$\begingroup$

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?

$\endgroup$
1
  • $\begingroup$ Yes! Thank you! $\endgroup$ Commented Jun 17, 2020 at 7:38
9
$\begingroup$

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

ConstantArray[Range[Max[s]], Length[s]] 
$\endgroup$
6
$\begingroup$

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] &] 

enter image description here enter image description here

$\endgroup$
1
  • $\begingroup$ PadRight is surprisingly fast! Wow! Flatten@, Join@@ or Catenate@ btw have quite different timings. but your PadRight stays faster… $\endgroup$ Commented Jun 17, 2020 at 12:33
3
$\begingroup$
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} 
$\endgroup$
2
$\begingroup$
(* 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 *) 
$\endgroup$
1
  • 1
    $\begingroup$ l = Length[s]; does not appear to be used? Also consider Cases[s, _ -> item] as Cases defaults to a levelspec of {1}. $\endgroup$ Commented Jun 20, 2020 at 13:37

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.