Mathematica Asked by garej on May 5, 2021
Say, we have a list:
m1 = {2, 2, 7, 0, 7, 7, 2, 2, 2}
It can be split easily:
Split @ m1
(* {{2, 2}, {7}, {0}, {7, 7}, {2, 2, 2}} *)
Wanted: a method to get the following list:
{{1, 2}, {3}, {4}, {5, 6}, {7, 8, 9}}
It should be as simple as possible and fast for long lists.
You can use
SplitBy[Range@Length@m1, m1[[#]] &]
Correct answer by Simon Woods on May 5, 2021
Perhaps:
s = Split@m1;
Internal`PartitionRagged[Range[Length@m1], Length /@ s]
Answered by ubpdqn on May 5, 2021
Using Mr.Wizard's ragged partition function here
dynP[l_, p_] := MapThread[l[[# ;; #2]] &,
{{0}~Join~Most@# + 1, #} &@Accumulate@p]
m1 = {2, 2, 7, 0, 7, 7, 2, 2, 2};
m2 = Split@m1;
dynP[Range@Length@m1, Length /@ m2]
{{1, 2}, {3}, {4}, {5, 6}, {7, 8, 9}}
Answered by Chris Degnen on May 5, 2021
Too late for the party so here's something old style:
Module[{i = 0}, Map[++i &, Split[m1], {-1}]]
or
SplitBy[MapIndexed[Flatten@*List, m1], First][[;; , ;; , 2]]
Answered by Kuba on May 5, 2021
I'll add another option, but be warned: It's rather slow.
FoldPairList[TakeDrop, Range@Length@m1, Length /@ (Split @ m1)]
Answered by V.E. on May 5, 2021
There is a complicated trade-off between the speed and compact form in this case, so I have decided to post the version with Range
, which I consider simple enough (comprehensible for new users) and second fast among the conterparts (at least, on my machine).
It is heavily based on @Mr.Wizard solution farsightedly provided by ChrisDegnen, so I do not claim originality:
dynS[p_] := Range @@@ Thread[{Accumulate@p - p + 1, Accumulate@p}]
And after looking at @Mr.Wizard SparseArray
solution I finally realize that we may use Listable
attribute of Range
to get even more compact version (this time I would prefer to keep pure function notation #
). So this is favorite method for me (not mine :)!
dynSP[p_] := Range[# - p + 1, #]& @ Accumulate @ p
I use the long list for benchmarking:
m1 = Flatten[Table[#, # + 1] & /@ RandomInteger[{1, 200}, 10^5]];
Length[m1]
(* 10156647 *)
And packed version later (second timing output in each method).
m1 = Developer`ToPackedArray[m1];
Range[Prepend[# + 1, 1], Append[#, Length @ m1]] &
@ SparseArray[Differences @ m1]["AdjacencyLists"] // Length // RepeatedTiming
(* {0.403, 99530} *)
(* {0.274, 99489} *)
dynSP[Length /@ Split @ m1] // Length // RepeatedTiming
(* {0.476, 99439} *)
(* {0.626, 99439} *)
dynS[Length /@ Split @ m1] // Length // RepeatedTiming
(* {0.506, 99495} *)
(* {0.715, 99489} *)
Internal`PartitionRagged[Range[Length@m1], Length /@ Split@m1] // Length // RepeatedTiming
(* {0.589, 99495} *)
(* {0.78, 99489} *)
dynP[Range@Length@m1, Length /@ Split @ m1] // Length // RepeatedTiming
(* {0.613, 99495} *)
(* {0.83, 99489} *)
Module[{i = 1}, Replace[Split@m1, _ :> i++, {-1}]] // Length // RepeatedTiming
(* {3.845, 99439} *)
(* {4.1, 99439} *)
Module[{i = 0}, Map[++i &, Split[m1], {-1}]] // Length // RepeatedTiming
(* {6.57, 99495} *)
(* {6.85, 99489} *)
SplitBy[Range @ Length @ m1, m1[[#]] &] // Length // RepeatedTiming
(* {24.6, 99495} *)
(* {25., 99489} *)
Note: fastest function with SparseArray
has been added a bit later so its result in terms of length is slightly different. The same is for the Module
with Split
version and my favorite DynSP
.
Answered by garej on May 5, 2021
SplitBy[Transpose[{m1, Range@Length@m1}], First][[;; , ;; , -1]]
or
m2 = Range@Length@m1;
i = 1; Split[m2, m1[[j = i++]] === m1[[j + 1]] &]
Answered by Basheer Algohi on May 5, 2021
m1 = {2, 2, 7, 0, 7, 7, 2, 2, 2};
Module[{i = 1}, Replace[Split@m1, _ :> i++, {-1}]]
(* {{1, 2}, {3}, {4}, {5, 6}, {7, 8, 9}} *)
Answered by march on May 5, 2021
Adapted from my answer to a related question:
runs[a_List] :=
Range[Prepend[# + 1, 1], Append[#, Length@a]] &@
SparseArray[Differences@a]["AdjacencyLists"]
Now:
runs @ {2, 2, 7, 0, 7, 7, 2, 2, 2}
{{1, 2}, {3}, {4}, {5, 6}, {7, 8, 9}}
Answered by Mr.Wizard on May 5, 2021
Internal`CopyListStructure
is quite fast:
Internal`CopyListStructure[Split @ #, Range @ Length @ #] & @ m1
{{1, 2}, {3}, {4}, {5, 6}, {7, 8, 9}}
Answered by kglr on May 5, 2021
Just wanted to belatedly add a new-style spin on Kuba's classic old-style answer, using the "Counter"
DataStructure
With[{counter = CreateDataStructure["Counter", 1]},
Map[counter["Increment"] &, Split[m1], {2}]]
(* {{1, 2}, {3}, {4}, {5, 6}, {7, 8, 9}} *)
Answered by Pillsy on May 5, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP