Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

How to make a function that splits list elements by odd and even positions? Shortest implementation wins. I myself came up with:

splitOdds[x_] := 
 Extract[x, {#}\[Transpose]] & /@ GatherBy[Range@Length@x, OddQ]

And:

splitOdds[x_] := Flatten[Partition[#, 1, 2]] & /@ {x, Rest@x}

splitOdds[{a, b, c, d, e, f}]
(*{{a, c, e}, {b, d, f}}*)
share|improve this question
1  
You can use Span e.g. Range[10][[;; ;; 2]] and Range[10][[2 ;; ;; 2]] –  Mr.Wizard Mar 16 '13 at 12:04
1  
The title and the text description of this question suggests something completely different. Further users will definitely be confused why you are not gathering even/odd elements, but elements on even/odd positions instead. –  halirutan Mar 16 '13 at 12:19
    
@halirutan I agree; I'll change it. –  Mr.Wizard Mar 16 '13 at 12:22
1  
How about Part[A, #] & /@ GatherBy[Range@Length@lst, OddQ] –  chyaong Mar 16 '13 at 14:00

10 Answers 10

up vote 13 down vote accepted

A couple for fun:

lst = {a, b, c, d, e, f, g};

Partition[lst, 2, 2, 1, {}] ~Flatten~ {2}
{{a, c, e, g}, {b, d, f}}
i = 1; GatherBy[lst, i *= -1 &]
{{a, c, e, g}, {b, d, f}}

And my Golf entry:

lst[[# ;; ;; 2]] & /@ {1,2}
{{a, c, e, g}, {b, d, f}}

And here is an anti-Golf "Rube Goldberg" solution:

ReleaseHold[List @@ Dot @@ 
  PadRight[{Hold /@ lst, {}}, Automatic, #]] & /@
    Permutations[Range[1, 0, -1]]
{{a, c, e, g}, {b, d, f}}
share|improve this answer
    
It's brilliant! –  swish Mar 16 '13 at 12:21
    
@swish Thanks. :-) –  Mr.Wizard Mar 16 '13 at 12:22
    
@swish Wait! Don't Accept an answer yet; you only just posted this. Give people a chance to answer. –  Mr.Wizard Mar 16 '13 at 12:25
    
Alright. It would be hard to beat but let's see. –  swish Mar 16 '13 at 12:27

Less than sensible, more than pretty, hopefully enjoyable, with a different notion of grouping. Based in part on this question. Gives a new meaning to bubble sort.

Movie of grouping Movie of grouping

list = {a, b, c, d, e, f, g(*, h, l, m, n, o, p, q, r, s, t*)};

likeElements[list_, {idx_}] /; OddQ[idx] := list[[1 ;; ;; 2]]; 
likeElements[list_, {idx_}] /; EvenQ[idx] := list[[2 ;; ;; 2]];
coords = Transpose[{Range[#], RandomReal[{-0.01, 0.01}, #], RandomReal[{-0.01, 0.01}, #]}] &@Length[list]; 

Dynamic[
 Refresh[Module[{d},
   Graphics3D[GraphicsComplex[
     coords -= MapIndexed[
       Total[Function[x, (d = # - x)/(d = Sqrt[d.d]) Log@d/2^(2 + 2 Sqrt[d])] /@ 
           Drop[likeElements[coords, #2], Ceiling[#2/2]]] + 
         Total[Function[x, -(d = # - x)/(d = Sqrt[d.d])^2 (d - 1/E) (1 - d/7)/2^(2 + 2 d)] /@ 
           likeElements[coords, #2 + 1]] &, coords],
    {MapIndexed[Text[Style[#1, ColorData[2][Mod[First[#2], 2]]], First[#2]] &, list],
     Opacity[0.3], Sphere[Range@Length[list], E^-1]}], 
    PlotRange -> {{-1.5, Length[list] + 1.5}, 4 {-1, 1}, 4 {-1, 1}}]
   ],
  UpdateInterval -> 1]]

Tweaking the coefficients slightly changes the behavior, which is also somewhat dependent on the length of the list. Won't win a speed contest.

The two Total[Function...] expressions calculate the new positions based on like elements (same parity) attract (first Total) and unlike repel (second Total).

share|improve this answer

You can also use Downsample, which is new in version 9:

lst = {a, b, c, d, e, f, g};
Downsample[lst, 2, #] & /@ {1, 2}
(* {{a, c, e, g}, {b, d, f}} *)
share|improve this answer
    
Oh neat, one new useful function learned. –  swish Mar 16 '13 at 16:28
    
+1 Nice. I hadn't found Downsample yet. –  Michael E2 Mar 16 '13 at 16:28
    
Is this function any faster than Part and Span, or Take? –  Mr.Wizard Mar 17 '13 at 6:58
    
@Mr.Wizard in my quick test, MMA 9.0.1, for packed arrays, better to worse, Downsample- Part- Take, but not for much. For unpacked, the opposite order –  Rojo Mar 17 '13 at 8:01
    
Thanks. It sounds like my old friend Part is still a good universal choice. :-) –  Mr.Wizard Mar 17 '13 at 8:04

Since all the sensible answers have already been done...

lst ~(•=#;Cases)~(_/;(•=!•))&/@{!#,#}&[_==_]
share|improve this answer
    
Oh great! Now this is going to start an obfuscated mma trend! –  rm -rf Mar 16 '13 at 15:02
    
This is really great. It's not often I have to do a double-take on syntax. :-O –  Mr.Wizard Mar 16 '13 at 15:26
1  
Will it rm -rf /* my disk? :) –  swish Mar 16 '13 at 16:31
1  
@swish I promise to not do anything to your disk ;) –  rm -rf Mar 16 '13 at 17:12
    
Ok, you've just got my wtf, I mean +1. I still haven't parsed it ... –  rcollyer Mar 16 '13 at 22:17

My way:

lst = {a, b, c, d, e, f, g};    

Take[lst, {#, -1, 2}] & /@ {1, 2}
{{a, c, e, g}, {b, d, f}}
share|improve this answer
    
That's mine, just longer. :-p –  Mr.Wizard Mar 16 '13 at 12:43
    
@Mr.Wizard Ha, I've just seen now that in the docs for Span it says m[[i;;j;;k]] is equivalent to Take[m,{i,j,k}]. Well, let's say that mine is more readable for novice users. –  VLC Mar 16 '13 at 12:49
    
Indeed it is. I'm just poking fun. :-) –  Mr.Wizard Mar 16 '13 at 12:54
    
By the way, try your hand at a "Rube Goldberg" solution. I had fun with mine, though it could be considerably more complicated... –  Mr.Wizard Mar 16 '13 at 12:55
    
I just timed these and Take is slightly faster. +1 for pragmatism. –  Mr.Wizard Mar 16 '13 at 13:08

Here is another one, based on Reap and Sow:

Reap[MapIndexed[Sow[#1, Mod[#2, 2]] &, lst], _, #2 &][[2]]

This one has an advantage to be easily generalizable to more complex conditions, although certainly not the fastest one here.

share|improve this answer
    
That looks too complicated. I would write: Reap[# ~Sow~ Mod[#2, 2] & ~MapIndexed~ lst][[2]] –  Mr.Wizard Mar 16 '13 at 13:54
    
@Mr.Wizard Yes, you can skip the pattern on Reap. But, generally, I am in the habit of keeping it, since I often use Reap with some tags just for safety. –  Leonid Shifrin Mar 16 '13 at 14:25

I'll join in with my own version:

splitList[list_] := Pick[list, 
    IntegerDigits[1/6 (-3 - (-1)^#1 + 2^(2 + #1)) &@Length@list, 2], #] & /@ {1, 0}

splitList[{a, b, c, d, e, f, g}]
(* {{a, c, e, g}, {b, d, f}} *)

This uses the fact that the "selector pattern" or "sieve" for the elements proceeds as

$$1, 10, 101, 1010, 10101,... $$

and the general term (in base 10) for the binary sequence above is $\frac{1}{6}(2^{2+n}-(-1)^n-3)$, where $n$ is the length of your list.

The selector pattern can also be generated more straightforwardly as:

Riffle[ConstantArray[1, Ceiling[Length@list/2]], 0]
share|improve this answer
    
Equivalently: splitList[l_List] := With[{n = Length[l]}, Pick[l, IntegerDigits[Ceiling[2 (2^n - 1)/3], 2, n], #] & /@ {1, 0}] –  J. M. May 6 '13 at 6:24

Method 1: GatherBy each element's position (even or odd).

GatherBy[lst, Mod[Position[lst,#],2]&]

{{a, c, e, g}, {b, d, f}}


Method 2: Using ArrayReshape (version 9).

Mathematica graphics

In the following, the MathematicaIcon is used for padding in the reshaping of the array. After the array is reshaped, the icons are removed. Any element can be used in lieu of the MathematicaIcon, provide that one is certain that the padding element is not in the original list.

 ArrayReshape[lst,{Length[lst],2},"\[MathematicaIcon]"]\[Transpose]
 /."\[MathematicaIcon]"->Sequence[]

Method 3: Check whether each index from MapIndexed is even or odd.

GatherBy[MapIndexed[List,lst],OddQ]/.{x_,{_}}:> x
share|improve this answer

Base on Pick:

gather[list_] := Pick[{list, list}, Take[#, Length@list] & /@ {#, RotateLeft[#]} &@
  Mod[Range@Ceiling[Length@list, 2], 2], 1];

gather[{a, b, c, d, e, f, g}]
{{a, c, e, g}, {b, d, f}}
share|improve this answer
    
g is in both your output lists! –  David Carraher Mar 17 '13 at 4:26
    
@DavidCarraher Doh! Thanks. That's funny, except I do need to see an optometrist. –  Michael E2 Mar 17 '13 at 12:29
# & @@@ # & /@ GatherBy[MapIndexed[{#, OddQ@#2} &, lst], Last]
#[[All, 1]] & /@ GatherBy[MapIndexed[{#, OddQ@#2} &, lst], Last]
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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