12

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?

user64494
  • 26,149
  • 4
  • 27
  • 56
no-one
  • 1,243
  • 9
  • 14

8 Answers8

14

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

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}}
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
6

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}}*)
Dr. belisarius
  • 115,881
  • 13
  • 203
  • 453
3

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}}*)
ubpdqn
  • 60,617
  • 3
  • 59
  • 148
2
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}}
march
  • 23,399
  • 2
  • 44
  • 100
Pankaj Sejwal
  • 2,063
  • 14
  • 23
2
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

eldo
  • 67,911
  • 5
  • 60
  • 168
2
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}}

Syed
  • 52,495
  • 4
  • 30
  • 85
2

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]]] *)
user1066
  • 17,923
  • 3
  • 31
  • 49