11
$\begingroup$

My question is similar to this one, but my goal is to prepend a single 0 the each sublist, not incrementally many 0's.

The file I'm working is a CSV containing around 50K sublists of length 35.

I've tried to Riffle my Flatten[list,1] and then Partition it into properly sized sublists, but the result isn't pretty - I might have to add an offset parameter.

Also, I'm trying to learn how to use pure functions, so any suggestion using them will be of help!

$\endgroup$
1
  • $\begingroup$ PadLeft[#,6]&/@lists $\endgroup$
    – yode
    Dec 8, 2023 at 2:20

6 Answers 6

22
$\begingroup$
lists = RandomInteger[{1, 9}, {4, 5}]
{{7, 4, 9, 9, 7},
 {4, 2, 5, 5, 2},
 {6, 5, 9, 2, 4},
 {1, 9, 4, 7, 2}}
ArrayPad[lists, {0, {1, 0}}]
{{0, 7, 4, 9, 9, 7},
 {0, 4, 2, 5, 5, 2},
 {0, 6, 5, 9, 2, 4},
 {0, 1, 9, 4, 7, 2}}

There are of course many ways to do this.

Since you are interested in learning here are some others, more or less practical:

Prepend[#, 0]& /@ lists

Prepend[0] /@ lists   (* version 10 operator form *)

Join[{0} & /@ lists, lists, 2]

{0, ##} & @@@ lists

lists /. {x__Integer} :> {0, x}

PadLeft[#, Dimensions@# + {0, 1}] &@lists

Rojo expressed doubt about the speed of ArrayPad. Here are some comparative timings using Packed Arrays, which one should use if speed is a concern:

lists = RandomInteger[99, {50000, 35}];

timeAvg = 
  Function[x, 
   Do[If[# > 1, Return[#/5^i]] & @@ Timing@Do[x, {5^i}], {i, 0, 15}], 
   HoldFirst];

Transpose@{ConstantArray[0, Length@#], Sequence @@ Transpose@#} &@lists // timeAvg

ArrayPad[lists, {0, {1, 0}}] // timeAvg

Join[0 ~ConstantArray~ {Length@#, 1}, #, 2] &@lists // timeAvg

ArrayFlatten@{{0, lists}} // timeAvg

0.00604

0.0019968

0.001224

0.0010032

ArrayFlatten is the fastest, taking 82% as long as Join/ConstantArray and 50% as long as ArrayPad.

Now an unpackable array (strings):

lists = RandomChoice["a" ~CharacterRange~ "z", {50000, 35}];

Transpose@{ConstantArray[0, Length@#], Sequence @@ Transpose@#} &@
  lists // timeAvg

ArrayPad[lists, {0, {1, 0}}] // timeAvg

Join[0 ~ConstantArray~ {Length@#, 1}, #, 2] &@lists // timeAvg

ArrayFlatten@{{0, lists}} // timeAvg

0.023464

0.024088

0.024088

0.08236

Here ArrayFlatten takes 342% and 351% as long as the other methods, which are all about the same.

Conclusion: use ArrayFlatten when you're sure the data is a packed array of the same type as the value you are inserting; use Join or ArrayPad when you are not.

$\endgroup$
6
  • 2
    $\begingroup$ Nice use of the last (numeric) argument of Join. I hadn't used it before, but will have to try and remember that one in future as it's clearly quite advantageous. $\endgroup$ Jul 6, 2012 at 22:40
  • $\begingroup$ Thanks. I've checked the speeds too, and here's what I got. PadLeft is fastest, with the rule trailing behind. $\endgroup$
    – CHM
    Jul 7, 2012 at 4:14
  • $\begingroup$ @CHM Of those I think PadLeft was fastest for me too, but notice that the Join method you tested is not the same as the faster one with ConstantArray, and ArrayPad is also missing. By the way, the one you labeled obscure is actually the easiest for me to read, but then I'm a freak for ## and @@@ so {0, ##} & @@@ x is pretty much Nirvana. lol $\endgroup$
    – Mr.Wizard
    Jul 7, 2012 at 9:13
  • $\begingroup$ @CHM thanks for the Accept! $\endgroup$
    – Mr.Wizard
    Jul 15, 2012 at 1:25
  • $\begingroup$ Thanks to you. At first, {0, ##} & @@@ lists was obscure, but I was looking for a pure function, and was served. Now, it seems natural. $\endgroup$
    – CHM
    Jul 15, 2012 at 1:27
12
$\begingroup$

One convenient method, originally due to Janus (see here):

list = {{1, 2}, {3, 4}, {5, 6}};   

ArrayFlatten@{{0, list}} 

giving

(* {{0, 1, 2}, {0, 3, 4}, {0, 5, 6}} *)

See here for some interesting comparisons by Timo

Edit

MapThread[Prepend[0],{list}]

(* {{0,1,2},{0,3,4},{0,5,6}} *)
$\endgroup$
1
  • $\begingroup$ Nice! I forgot about this one. I need to add it to my timings. $\endgroup$
    – Mr.Wizard
    Jul 8, 2012 at 11:51
11
$\begingroup$
list = {{1, 2}, {3, 4}, {5, 6}};    
Flatten /@ Tuples[{{0}, list}]
{{0, 1, 2}, {0, 3, 4}, {0, 5, 6}}
Join @@@ Tuples[{{{0}}, list}]

the latter method (thanks to kguler) is even faster than the former one.

These toys haven't been mentioned yet :

Join[ {0}, #] & /@ list

Flatten /@ ({0, #} & /@ list)

MapThread[ Join, {ConstantArray[{0}, Length @ list], list}]

Thread[Join[{0}, Transpose@list]]
$\endgroup$
3
  • $\begingroup$ @Rojo Thanks, I wanted to use Tuples since sometimes it appears to be the best, look here e.g. mathematica.stackexchange.com/questions/4748/… $\endgroup$
    – Artes
    Jul 6, 2012 at 22:18
  • 2
    $\begingroup$ +1, or Join @@@ Tuples[{{{0}}, lists}]:)? $\endgroup$
    – kglr
    Jul 6, 2012 at 23:39
  • $\begingroup$ @kguler Thanks, I'll add this, seems even faster than Flatten /@ Tuples[{{0}, list}]. $\endgroup$
    – Artes
    Jul 6, 2012 at 23:54
8
$\begingroup$

One (exotic) way is by using Flatten with its second argument (thanks to Oleksandr for fixing my Flatten). For example:

list= {{1, 2}, {3, 4}, {5, 6}};
Flatten[{ConstantArray[{0}, Length@#], #}, {{2}, {3, 1}}] &@list
(* {{0, 1, 2}, {0, 3, 4}, {0, 5, 6}} *)    

See this answer by Leonid for a detailed explanation on how Flatten's second argument works.

However, this is "slow". Another possibility that's much faster than the above is

Transpose@{ConstantArray[0, Length@#], Sequence @@ Transpose@#} &@list

A rule based solution for doing the same would be:

list /. {x__?NumericQ} :> {0, x};

If your list isn't very large (and your CSV file is very modest), then this is perhaps the clearest in intent.

$\endgroup$
11
  • $\begingroup$ I beat you to the replacement rule. :^) Also, you may need to restrict it a bit... $\endgroup$
    – Mr.Wizard
    Jul 6, 2012 at 22:04
  • $\begingroup$ This question is your 80th in this tag, which means you get a silver tonight. Congrats! $\endgroup$
    – rm -rf
    Jul 6, 2012 at 22:12
  • $\begingroup$ @OleksandrR. Thanks! I was trying that and observed that {{2}, {3}} and {{2}, {1}} gave similar, but differently grouped lists and couldn't figure out how to combine them other than with a Flatten/@. I'll add that in $\endgroup$
    – rm -rf
    Jul 6, 2012 at 22:21
  • $\begingroup$ @Oleksandr your method however is considerably slower on the test used on my answer. $\endgroup$
    – Mr.Wizard
    Jul 6, 2012 at 22:24
  • 2
    $\begingroup$ @Oleksandr Leonid seems to have a better handle on that, but I have to rely on testing, memory, and On["Packing"]. Using Join over Flatten when possible is one of the heuristics I've picked up. $\endgroup$
    – Mr.Wizard
    Jul 6, 2012 at 23:01
2
$\begingroup$

Using Cases:

list = {{7, 4, 9, 9, 7}, {4, 2, 5, 5, 2}, {6, 5, 9, 2, 4}, {1, 9, 4, 7, 2}};

Cases[list, x : {__} :> {0, Sequence @@ x}]

(*{{0, 7, 4, 9, 9, 7}, {0, 4, 2, 5, 5, 2}, {0, 6, 5, 9, 2, 4}, {0, 1, 9,4, 7, 2}}*)
$\endgroup$
2
$\begingroup$

It's a bit strange for me that no answer used Riffle

With

list = RandomInteger[{1, 9}, {4, 5}];
zero = 0~ConstantArray~{Length@list};

we do:

ArrayReshape[
 Riffle[zero, 
  list], {(Dimensions@list)[[1]], (Dimensions@list)[[2]] + 1}]

and we have

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

from the input

list

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

and also

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.