3
$\begingroup$

I can not make sure, but I have searched this website, there is not the same question as what I will ask below. If it turns out there indeed exists, please let me know, thanks a lot.

My question is not complicated, actually. Suppose I have a List of Length 32:

values = RandomInteger[9, 32];

A baby question

If I want to divide it into two groups, e.g., by naming that the 3rd to 6th elements are in Group I and the rest are in Group II, I can use TakeDrop to easily satisfy myself:

TakeDrop[values, {3, 6}]

The advantage of TakeDrop is that the user need not provide the information for Group II explicitly.

The real question

Well, what I really want to put into Group I, besides the 3rd to 6th elements, in the meanwhile includes also the 13th to 16th elements, namely, the position specification is not in a consecutive fashion. At first, I guessed TakeDrop maybe also to work, but did not find a way out. And what so far I can come up with is to use Part with Complement, something like:

{#[[{3, 4, 5, 6, 13, 14, 15, 16}]], #[[Complement[Range[32], {3, 4, 5, 6, 13, 14, 15, 16}]]]} &[values]

which, frankly speaking, I do not think very pretty, in that I have to write code to calculate the positions for Group II.

So, is there a way like TakeDrop working for my real question?

$\endgroup$

2 Answers 2

3
$\begingroup$
ClearAll[foldTakeDrop]
foldTakeDrop =  Fold[Function[{x, y}, {Join[#, First[x]], #2} & @@ 
      TakeDrop[Last@x, y]], {{}, #}, Reverse[#2]] &;

Examples:

SeedRandom[1]
values = RandomInteger[9, 32]
{1, 4, 0, 7, 0, 0, 8, 6, 0, 4, 1, 8, 5, 1, 1, 1, 3, 2, 1, 6, 0, 2, 6, 4, 5, 
 4, 3, 0, 1, 3, 5, 3}
foldTakeDrop[values, {{3, 6}, {13, 16}}]
{{0, 7, 0, 0, 5, 1, 1, 1}, 
 {1, 4, 8, 6, 0, 4, 1, 8, 3, 2, 1, 6, 0, 2, 6, 4, 5, 4, 3, 0, 1, 3, 5, 3}}
MapAt[Style[#, Red] &, values, List /@ Join[Range[3, 6], Range[13, 16]]]

>

foldTakeDrop[values, {{3, 6}, {13, 16}, {22, 28, 2}}]
{{0, 7, 0, 0, 5, 1, 1, 1, 2, 4, 4, 0}, 
 {1, 4, 8, 6, 0, 4, 1, 8, 3, 2, 1, 6, 0, 6, 5, 3, 1, 3, 5, 3}}
MapAt[Style[#, Red] &, values, 
 List /@ Join[Range[3, 6], Range[13, 16], Range[22, 28, 2]]]

enter image description here

Update: Alternative methods:

ClearAll[thruExtractDelete, foldPairs]

thruExtractDelete = Through[{Extract, Delete}[#, List /@ Join @@ Range @@@ #2]] &;

foldPairs = {Flatten@Reverse@#[[All, All, 1]], #[[-1, -1, -1]]} &@
    FoldPairList[TakeDrop, #, Reverse@#2, List] &;





foldPairs[values, {{3, 6}, {13, 16}}] == 
 thruExtractDelete[values, {{3, 6}, {13, 16}}] == 
  foldTakeDrop[values, {{3, 6}, {13, 16}}]
  True
foldPairs[values, {{3, 6}, {13, 16}, {22, 28, 2}}] == 
 thruExtractDelete[values, {{3, 6}, {13, 16}, {22, 28, 2}}] == 
   foldTakeDrop[values, {{3, 6}, {13, 16}, {22, 28, 2}}]
  True
$\endgroup$
1
  • 1
    $\begingroup$ Hello, thanks for the answer, which fortunately works more like what I want; then, unfortunately, it seems no builtin function to work. $\endgroup$ Commented May 6, 2020 at 8:07
2
$\begingroup$

Group I, besides the 3rd to 6th elements, in the meanwhile includes also the 13th to 16th elements, namely, the position specification is not in a consecutive fashion

If I understand you right:

 values=RandomInteger[9,32]
 (*{1,6,7,9,3,9,4,8,4,7,1,7,1,3,5,3,3,6,5,1,1,0,2,8,4,7,8,7,6,7,9,3}*)

  p = Join[ Range[3, 6], Range[13, 16] ];
  (*{3, 4, 5, 6, 13, 14, 15, 16}*)

The above are the positions of elements to delete. Part accepts non consecutive positions.

  group1 = values[[ p ]]

  (* {7, 9, 3, 9, 1, 3, 5, 3} *)

To remove group1 from original list, one way is to use Delete. But Delete wants positions as {{1},{2},..} and not as {1,2,...}, so add extra {}

  group2 = Delete[values, List[#] & /@ p];
  (*{1, 6, 4, 8, 4, 7, 1, 7, 3, 6, 5, 1, 1, 0, 2, 8, 4, 7, 8, 7, 6, 7, 9,  3}*)

And now

  {group1, group2}

gives

{{7, 9, 3, 9, 1, 3, 5, 3}, 
 {1, 6, 4, 8, 4, 7, 1, 7, 3, 6, 5, 1, 1, 0, 2, 8, 4, 7, 8, 7, 6, 7, 9, 3}}
$\endgroup$
4
  • $\begingroup$ Thanks for the quick response! I think your code understands what process to undergo and can obtain the right result. But it is not exactly what I want. $\endgroup$ Commented May 6, 2020 at 7:48
  • $\begingroup$ @ΑλέξανδροςΖεγγ I do not understand, It gives same result as you show. Did you try {group1, group2} ? $\endgroup$
    – Nasser
    Commented May 6, 2020 at 7:53
  • $\begingroup$ I have to apologize, maybe I did not express myself very clearly. I have added additional information. Thanks a lot again. $\endgroup$ Commented May 6, 2020 at 7:53
  • $\begingroup$ Yes, I believe your code can give the right result. $\endgroup$ Commented May 6, 2020 at 7:54

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.