ArrayRules for a ragged list

Let there be a sample list as ,

l = {a, {{b, c}}, {d, e}, {f}, {{g, {y}, u, h}, {{{{k, j}}}}},k, {{{{q}, {w}, {r}, {x}}}}};
ArrayRules[l]

ArrayRules::rect: Nonrectangular array encountered. >>

is the error thrown. So, I was just wondering that if someone needs to preserve list structure using a similar kind of functionality, than what might be the steps needed. My intention is to pass data to replace later rather than as rule in ArrayRules.
I could parse list to find positions information like ArrayRules using following code,

ListRules[l_List] :=
Module[{l1 = l, l11, s1, pos, M, tpos, trpos, sp, ntrpos, temntrpos,
fin, fin2},
{l11 = {#} & /@ l1,
s1 = Map[{#, Position[l11, #]} &, l11,Infinity] /. {a_, {{s___}}} -> {s} //. {d___, {}, e___} -> {d,e},
pos = Table[s1[[i]] //. {___, {a___List}, ___} -> a, {i, 1,Length[s1]}],
M = Last[SortBy[pos, Length]] // Length,
tpos = Table[If[Length[pos[[i]]] < M, PadRight[pos[[i]], M, 1], pos[[i]]], {i, 1, Length[pos]}], }; tpos] listrules= ListRules[l] {{1, 1, 1, 1, 1, 1, 1}, {2, 1, 1, 1, 1, 1, 1}, {2, 1, 1, 2, 1, 1, 1}, {3, 1, 1, 1, 1, 1, 1}, {3, 1, 2, 1, 1, 1, 1}, {4, 1, 1, 1, 1, 1, 1}, {5, 1, 1, 1, 1, 1, 1}, {5, 1, 1, 2, 1, 1, 1}, {5, 1, 1, 3, 1, 1, 1}, {5, 1, 1, 4, 1, 1, 1}, {5, 1, 2, 1, 1, 1, 1}, {6, 1, 1, 1, 1, 1, 1}, {5, 1, 2, 1, 1, 1, 2}, {5, 1, 2, 1, 1, 1, 1}, {6, 1, 1, 1, 1, 1, 1}, {7, 1, 1, 1, 1, 1, 1}, {7, 1, 1, 1, 2, 1, 1}, {7, 1, 1, 1, 3, 1, 1}, {7, 1, 1, 1, 4, 1, 1}} Than I tried to create it back to a list using following method, CreateList[s_List] := Module[{tpos = s, trpos, sp, ntrpos, temntrpos, t, x, y, h}, {trpos =Table[tpos[[i]] -> RandomInteger[100], {i, 1,Length[tpos]}],
sp = SparseArray[trpos],
ntrpos = Normal[sp],
temntrpos = ntrpos //. {a___, {h___, 0 ..}, b___} -> {a, h, b} //. {a___, {}, b___} -> {a, b}
}; temntrpos
]
CreateList[listrules]

gives,

{{{{{{76}}}}}, {{{{{82}}, {{83}}}}}, {{{{{67}}}, {{{19}}}}}, {{{{{32}}}}}, {{{{{51}}, {{22}}, {{60}}, {{1}}}, {{{{26,59}}}}}}, {{{{{12}}}}}, {{{{{6}, {78}, {34}, {72}}}}}}

It shows that it has been able to retain nesting structure but there are extra braces associated. I tried to use Dimension, Depth etc. I can get rid of nesting for single elements by associating dimension from original list with them and flattening all those with maximum dimension as 1 for Rest[sublist]. But in case of multiple nesting, I am failing. I have to keep number of braces same in both source and destination.

=================

=================

3 Answers
3

=================

If I understood correctly, what you might want is this:

Flatten @ MapIndexed[(#2 -> #1 &), l, {-1}]

{ {1} -> a, {2,1,1} -> b, {2,1,2} -> c, {3,1} -> d, {3,2} -> e,
{4,1} -> f, {5,1,1} -> g, {5,1,2,1} -> y, {5,1,3} -> u, {5,1,4} -> h,
{5,2,1,1,1,1} -> k, {5,2,1,1,1,2} -> j, {6} -> k, {7,1,1,1,1} -> q,
{7,1,1,2,1} -> w, {7,1,1,3,1} -> r, {7,1,1,4,1} -> x }

Is it right?

  

 

No that’s not what I am looking for actually. Though thanks for suggestion, I am aware of this already.
– Rorschach
Nov 9 ’13 at 14:09

I interpret your question as asking how to use a given list as a template for building a tree, your goal being to produce a new tree with the same structure as the given one, but withe new leaves extracted from a second list. If my interpretation is correct, you can proceed as follows:

tree =
{a, {{b, c}}, {d, e}, {f}, {{g, {y}, u, h}, {{{{k, j}}}}}, k, {{{{q}, {w}, {r}, {x}}}}};
leaves = tree // Flatten;
SeedRandom[42]; data = RandomInteger[100, Length @ leaves];
rules = Thread[Rule[leaves, data]];
dataTree = tree /. rules

{54, {{66, 4}}, {15, 6}, {3}, {{95, {32}, 48, 3}, {{{{81, 87}}}}}, 81,
{{{{88}, {98}, {48}, {44}}}}}

  

 

Your interpretation is correct but this will replace elements rather than preserving list structure. It is escaping the significance of list format.
– Rorschach
Nov 9 ’13 at 14:20

  

 

@Blackbird. I don’t understand your comment. My approach preserves the structure of the template list exactly.
– m_goldberg
Nov 9 ’13 at 15:53

  

 

Sorry for unclear comment,I meant to say that I want to follow the approach I am using. I need to associate some info with each sublist that decides number of braces.I hope I could make myself more clear.
– Rorschach
Nov 9 ’13 at 17:22

It is not clear to me exactly what you want. If user8074’s method is helpful you may also consider using Position as follows which will work with non-atomic elements as well.

l = {a, {{b, c}}, {d, e}, {f}, {{g, {y}, u, h}, {{{{k, j}}}}},
k, {{{{q}, {w}, {r}, {x}}}}};

pos = Position[l, Except[_List], Heads -> False]

{{1}, {2, 1, 1}, {2, 1, 2}, {3, 1}, {3, 2}, {4, 1}, {5, 1, 1}, {5, 1, 2, 1}, {5, 1, 3},
{5, 1, 4}, {5, 2, 1, 1, 1, 1}, {5, 2, 1, 1, 1, 2}, {6}, {7, 1, 1, 1, 1}, {7, 1, 1, 2, 1},
{7, 1, 1, 3, 1}, {7, 1, 1, 4, 1}}

You can Extract the elements using those positions:

elem = Extract[l, pos]

{a, b, c, d, e, f, g, y, u, h, k, j, k, q, w, r, x}

You can also replace the elements using ReplacePart:

new = Range[17];

ReplacePart[l, Thread[pos -> new]]

{1, {{2, 3}}, {4, 5}, {6}, {{7, {8}, 9, 10}, {{{{11, 12}}}}}, 13,
{{{{14}, {15}, {16}, {17}}}}}

Does this help?

  

 

No doubt this solves the problem but I am trying to work it through Sparse array,because preserving information this way, I can use it to create sparse array or NonSparse array. My precise question is that what information I shall associate with each sublist that it will help me put right number of parenthesis.
– Rorschach
Nov 9 ’13 at 14:14