# Split according to List and apply rule

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?

• The first part of your question I answered here: (7511) Dec 3 '15 at 23:16

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

Fold[Rule, #] & /@
InternalPartitionRagged[{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 /@
InternalPartitionRagged[{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@#]} & /@
InternalPartitionRagged[{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10}, {1, 2, 3, 4}]

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

• With // Partition[#, 1] & in the end to yield the exact requested output. Dec 3 '15 at 18:05
• @anderstood. Or {#} &/@ result. Dec 3 '15 at 18:29
• @march List /@ result is probably clearer for a beginner Dec 3 '15 at 18:56
• @belisariushassettled. And for an established user/expert, too. Dec 3 '15 at 18:57

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]]]


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}}


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}}*)

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

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

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


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}}*)
`