12
$\begingroup$

I have a list which looks some thing like this

{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10}

Now I want to split it according to lengths {1,2,3,4} so that I would have

{{a1},{ a2, a3}, {a4, a5, a6},{ a7, a8, a9, a10}}

and I want to apply the rule with itself. For example: after rule application, the answer should become

{{a1},{a2->a3},{a4->a5->a6},{a7->a8->a9->a10}}.

I have tried to use Split and Partition function but not getting the desired result. Is there any other function that accomplishes this? If not how can I do this?

$\endgroup$
1
  • $\begingroup$ The first part of your question I answered here: (7511) $\endgroup$
    – Mr.Wizard
    Dec 3, 2015 at 23:16

8 Answers 8

14
$\begingroup$

Depending on the precedence you want for Rule, you can use either

Fold[Rule, #] & /@ 
 Internal`PartitionRagged[{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10}, {1, 2, 3, 4}]

(* {a1, a2 -> a3, (a4 -> a5) -> a6, ((a7 -> a8) -> a9) -> a10} *)

or

Fold[Rule[#2, #1] &, #] & /@ Reverse /@ 
 Internal`PartitionRagged[{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10}, {1, 2, 3, 4}]

(* {a1, a2 -> a3, a4 -> a5 -> a6, a7 -> a8 -> a9 -> a10} *)

To end up with the requested output, you can evalute List /@ on the resulting expressions.

Update

To avoid mapping twice in the last solution, one could use Fold[Rule[#2, #1] &, Reverse@#] & instead of Fold[Rule[#2, #1] &, #] & /@ Reverse.

Also, instead of using List /@ on the output as suggested above, one could directly enclose the Fold function between braces, e.g.

{Fold[Rule[#2, #1] &, Reverse@#]} & /@ 
  Internal`PartitionRagged[{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10}, {1, 2, 3, 4}]

(* {{a1}, {a2 -> a3}, {a4 -> a5 -> a6}, {a7 -> a8 -> a9 -> a10}} *)
$\endgroup$
4
  • 2
    $\begingroup$ With // Partition[#, 1] & in the end to yield the exact requested output. $\endgroup$
    – anderstood
    Dec 3, 2015 at 18:05
  • $\begingroup$ @anderstood. Or {#} &/@ result. $\endgroup$
    – march
    Dec 3, 2015 at 18:29
  • 1
    $\begingroup$ @march List /@ result is probably clearer for a beginner $\endgroup$ Dec 3, 2015 at 18:56
  • 2
    $\begingroup$ @belisariushassettled. And for an established user/expert, too. $\endgroup$
    – march
    Dec 3, 2015 at 18:57
8
$\begingroup$

The partitioning aspect of your question is already addressed in detail in Partitioning with varying partition size.

The second aspect of your question amounts to performing a right fold. For the case at hand this might be done most easily using pattern matching:

rule[a___, x_, y_] := rule[a, x -> y]
rule[x_] := x

This is essentially a multi-argument Rule with a defined precedence. It does this:

rule[a1, a2, a3, a4]
a1 -> a2 -> a3 -> a4

You can then Apply this function to a list, or list of lists. Using my partitionBy function from the referenced Q&A your operation is then:

in = {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10};

List /@ rule @@@ partitionBy[in, # &]
{{a1}, {a2 -> a3}, {a4 -> a5 -> a6}, {a7 -> a8 -> a9 -> a10}}

Xavier also provided a right fold method, and one that can be much more efficient in certain cases due to the optimizations within Fold. Let's make it an abstraction, and add an Operator Form while we're at:

Default[foldr] = Sequence[];
foldr[f_][p__] := foldr[f, p]
foldr[f_, x_., a : _[__]] := Fold[#2 ~f~ #1 &, x, Reverse @ a]

It does this:

foldr[oo][{a1, a2, a3, a4}]
oo[a1, oo[a2, oo[a3, a4]]]

Your operation is then:

in = {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10};

List /@ foldr[Rule] /@ partitionBy[in, # &]
{{a1}, {a2 -> a3}, {a4 -> a5 -> a6}, {a7 -> a8 -> a9 -> a10}}
$\endgroup$
6
$\begingroup$

If you don't want to use the handy but undocumented PartitionRagged, you could go by:

l  = {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10}; 
r = Range[1/2 (-1 + Sqrt[1 + 8 Length@l])]
ls = Transpose@{# - PadLeft[Most@r, Length@r], #} &@Accumulate@r;
l[[#1 ;; #2]] & @@@ ls

(*{{a1}, {a2, a3}, {a4, a5, a6}, {a7, a8, a9, a10}}*)
$\endgroup$
7
  • $\begingroup$ "List /@ result is probably clearer for a beginner" – belisarius has settled 16 mins ago :) $\endgroup$
    – Kuba
    Dec 3, 2015 at 19:14
  • $\begingroup$ @Kuba What am I missing?:( $\endgroup$ Dec 3, 2015 at 19:19
  • 1
    $\begingroup$ A solution clear for beginner :) $\endgroup$
    – Kuba
    Dec 3, 2015 at 19:20
  • 1
    $\begingroup$ @Kuba Ahhh ... that's Xavier's ! :D $\endgroup$ Dec 3, 2015 at 19:21
  • 2
    $\begingroup$ A documented alternative to PartitionRagged could be: FoldPairList[TakeDrop, {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10}, {1, 2, 3, 4}]. $\endgroup$
    – user31159
    Dec 3, 2015 at 19:44
3
$\begingroup$

Just for something different:

pf[lst_, pt_] := Module[{p = Join @@ (Table[#, {#}] & /@ pt)},
  Last@Reap[Inner[Sow, lst, p, List], _, #2 &]]

So,

m = {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10};
pf[m, {1, 2, 3, 4}]

yields:

(*{{a1}, {a2, a3}, {a4, a5, a6}, {a7, a8, a9, a10}}*)
$\endgroup$
2
$\begingroup$
lst = {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10};
ord = {1, 2, 3, 4}

Prepend[
  Map[Take[lst, #] &,
    Map[{#[[1]] + 1, #[[2]]} &, Partition[Accumulate[ord], 2, 1]]
   ],
  {lst[[1]]}
 ] //. {a___, {b_, c_, p___}, d___} :> {a, {b -> c, p}, d}

{{a1}, {a2 -> a3}, {(a4 -> a5) -> a6}, {((a7 -> a8) -> a9) -> a10}}
$\endgroup$
2
$\begingroup$
list = {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10};

{ToExpression @ StringRiffle[#, "->"]} & /@ TakeList[list, {1, 2, 3, 4}]

{{a1}, {a2 -> a3}, {a4 -> a5 -> a6}, {a7 -> a8 -> a9 -> a10}}

TakeList since V 11.2 and StringRiffle since V 10.1

$\endgroup$
2
$\begingroup$
Clear["Global`*"];
list = {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10};
t = TakeList[list, {1, 2, 3, 4}];
TextString[#, ListFormat -> {"{ ", "->", " }"}] & /@ t // ToExpression

{{a1}, {a2 -> a3}, {a4 -> a5 -> a6}, {a7 -> a8 -> a9 -> a10}}

$\endgroup$
2
$\begingroup$

Update

(1)

List@*ResourceFunction["FoldRight"][Rule] /@ 
  TakeList[{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10}, {1, 2, 3, 4}]

(* {{a1}, {a2 -> a3}, {a4 -> a5 -> a6}, {a7 -> a8 -> a9 -> a10}} *)

(2)

List@Fold[ReverseApplied[Rule], #1, ##2] & /@ 
  Reverse[TakeList[{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10}, {1, 2, 3, 4}], 2]

(* {{a1}, {a2 -> a3}, {a4 -> a5 -> a6}, {a7 -> a8 -> a9 -> a10}} *) 

Right Fold

ResourceFunction["FoldRight"][f]@{a, b, c, d}

(* f[a, f[b, f[c, d]]] *)
Fold[ReverseApplied[f], #1, ##2] &@Reverse[{a, b, c, d}]

(* f[a, f[b, f[c, d]]] *)
$\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.