5
$\begingroup$

Consider the below list

testlist = {0, 1, 2, 0, 0, 1, "a", "b", "c", "d", "e", "f"}

I am trying to group every two numbers and every two letters in a list, and in the end form the following result:

reslist={{0, 1, a, b},{2, 0, c, d}, {0, 1, e, f}}

What I do is the following:

testmp= Partition[testlist, 2];
reslist = {};
 For[ii = 1, ii <= Length[testmp]/2, ii++,
  AppendTo[reslist, {testmp[[ii]], testmp[[ii + Length[testmp]/2]]}]
  ];

Q: Is there simple way to do it? Furthermore, when the testlist is described by CombineList and gets larger, how one can efficiently do it? I find some links which potentially works but I failed to use it.

value = {{0, 1, 2, 0, 0, 1}, {0, 1, 2, 0, 0, 2}, {0, 1, 2, 0, 1, 0}, {0, 1, 2, 0, 1, 1}};
label = {{"a", "b", "c", "d", "e", "f"}, {"a", "b", "d", "f", "c", "e"}};
CombineList = Array[Join[value[[#2]], label[[#]]] &, Length /@ {label, value}]

one example:

testlist={{0, 1, 2, 0, 0, 1, "a", "b", "c", "d", "e", "f"}, {0, 1, 2, 0, 0, 1, 
  "a", "b", "d", "f", "c", "e"}}

the result could be something like the following

{ {{0, 1, a, b},{2, 0, c, d}, {0, 1, e, f}}, {{0, 1, a, b},{2, 0, d, f}, {0, 1, c, e}} }

Thank you!

$\endgroup$
4
  • 3
    $\begingroup$ This function will do what you need, for your testlist at least: Flatten[TakeDrop[#, Length[#]/2] & @Partition[#, 2], {{2}, {1, 3}}] &. You use it as e.g. Flatten[TakeDrop[#, Length[#]/2] & @Partition[#, 2], {{2}, {1, 3}}] & @ testlist. $\endgroup$ May 25 at 16:05
  • $\begingroup$ @LeonidShifrin, thank you! that's a good solution for simple lists. does it also work for nested list? Or one have to do some for-loop things? $\endgroup$
    – Xuemei
    May 25 at 16:12
  • 1
    $\begingroup$ Simply Map[function-above, your-nested-list]. $\endgroup$ May 25 at 16:45
  • $\begingroup$ thank you so much! that helps a lot!@LeonidShifrin $\endgroup$
    – Xuemei
    May 25 at 16:46
5
$\begingroup$
testlist = {{0, 1, 2, 0, 0, 1, "a", "b", "c", "d", "e", "f"}, 
  {0, 1, 2, 0, 0, 1, "a", "b", "d", "f", "c", "e"}}

reShape1 = Join[##, 2] & @@ ArrayReshape[#, {2, 3, 2}] &;

Map[reShape1] @  testlist
 {{{0, 1, "a", "b"}, {2, 0, "c", "d"}, {0, 1, "e", "f"}},
  {{0, 1, "a", "b"}, {2, 0, "d", "f"}, {0, 1, "c", "e"}}}

Also

reShape2 = Join @@@ Transpose @ ArrayReshape[#, {2, 3, 2}] &;
reShape3 = Flatten[ArrayReshape[#, {2, 3, 2}], {{2}, {1, 3}}] &;
reShape4 = ArrayReshape[Transpose @ ArrayReshape[#, {2, 3, 2}], {3, 4}] &;
reShape5 = Transpose @ Fold[Transpose @* ArrayReshape, #, {{2, 3, 2}, {3, 4}}] &;

Equal @@ (Map[#] @ testlist & /@ 
  {reShape1, reShape2, reShape3, reShape4, reShape4})
 True
$\endgroup$
3
  • $\begingroup$ This is a comment regarding the first suggestion you made. I am getting an error when I run the commands. If I use instead reShape1@testlist it gives the desired output $\endgroup$ May 27 at 12:07
  • 1
    $\begingroup$ Thank you @DiSp0sablE_H3r0. I used OP's second input list (also named testlist). $\endgroup$
    – kglr
    May 27 at 12:14
  • 1
    $\begingroup$ Thanks for clarifying and updating the answers. Excellent answer as always btw! +1 from me $\endgroup$ May 27 at 12:16
3
$\begingroup$

Here's a way that generalizes to lists of arbitrary length, provided that they are well-formed (with an even number of integer and string elements, and the same number of integer and string elements):

Catenate /@ 
 Transpose[
  SequenceCases[testlist, {Blank@#, Blank@#}] & /@ {Integer, String}],
(* {{0, 1, "a", "b"}, {2, 0, "c", "d"}, {0, 1, "e", "f"}} *)
$\endgroup$
1
  • $\begingroup$ nice way to create binary files, thank you! $\endgroup$
    – Xuemei
    May 27 at 16:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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