Message Boards Message Boards

0
|
3258 Views
|
10 Replies
|
1 Total Likes
View groups...
Share
Share this post:

Converting structured nested lists to Associations.

Posted 3 years ago

I would like to convert a format like this:

{"y", {"a", "b", e}, {"c", g, h}, {"d", v, u}...}

The first item of each list is a string, the rest of the list is a mixture of strings or list. Goal to Convert

{"y", {"a", "b", e}, {"c", g, h}, {"d", v, u}}  

to this:

<|"y"-> {"a"-> {"b", e}, "c"->{g, h}, "d"-> {v, u} }|>

I tried this as part of my efforts:

asscnvt1[l_List] :=  First@l -> Rest@l; 
asscnvt1 /@ {"y", {"a", "b", e}, {"c", g, h}, {"d", v, u}}

which gives:

{asscnvt["y"], "a" -> {"b", e}, "c" -> {g, h}, "d" -> {v, u}} 

which worked, but not handling the outer most list starting with "y".

So how do I handle the outermost list? Tried searching for a recursive function to do this but could not find one. Thanks for your help.

POSTED BY: Andrew Meit
10 Replies
Posted 3 years ago

adding a screenshot for others to understand better. The structure of the lists as a database as shown here is common, at least to me. Eric, please consider making any additional robustness needed for polish. I think others would enjoy using your code. Thanksenter image description here

POSTED BY: Andrew Meit
Posted 3 years ago

Well done! Thank you. Now I can move forward using a more robust dataset to rework and easily add to; finish a long term project started in 2009. Manually reworking dataset with my fingers was not something I wanted to endure (am disabled). Off to test the rest of the dataset; will report later on. I can code thusly:

WLDM["Language", "Lists", "List Parts"] 

which returns the functions I want all semantically not scrolling a long list of words. If it was easy code, I would have found code already. I will learn much from your elegant code. :-) Happy dance!

POSTED BY: Andrew Meit
Posted 3 years ago

Since you are defining your core data explicitly, why didn't you just define it as the Association structure that you wanted?

POSTED BY: Eric Rimbey
Posted 3 years ago

Sorry, it was intented to just be applied to your data, not used as a replacement rule. But it still doesn't quite work now that I understand your data structure (I hope).

So, trying this again. The problem is that the semantics of a list changes as we traverse down the nested lists (sometimes we want to deconstruct the list into a rule, sometimes we want the list to be a rule, and sometimes we want a list to be deconstructed into an Association). I think you could do it all in one step, but I'll break it into pieces. I'll be going back to the strategy of replacing List with functions that do the work.

StringsToRule[k_String, rest__String] := Rule[k, {rest}];
StringsToRule[else___] := {else};

StringsToRule works at the lowest level, turning lists of strings into rules such that the first element is the "key" and the rest become a new list as the "value".

RulesToAssociation[k_String, rest__Rule] := Rule[k, Association[rest]];
RulesToAssociation[else___] := {else};

RulesToAssociation will be applied after StringsToRule. At that point, we should have lists that start with a string and finish with a string of Rules. The Rules can be bundled up into an Association and attached to the string "key". We could do a similar thing with Associations, but it looks like you just have one pair in the largest scope, so we can just wrap the whole thing with a single Association.

Here we go, applying the pieces in turn:

core /. List -> StringsToRule /. List -> RulesToAssociation // Association

I'll give the same caveat: I'm still making assumptions. Maybe a different version of this kind of data would be mishandled.

POSTED BY: Eric Rimbey
Posted 3 years ago

it was supposed to attach the notebook not put its contents in the post.

POSTED BY: Andrew Meit
Posted 3 years ago

Attaching a notebook of sample data. Sorry for not being fully clearer about the association nesting. I assume this is how am supposed to use your new code:

AsAssociation[list_List /; FreeQ[list, List, {2}]] := list;
AsAssociation[{k_, rest_}] := <|k -> AsAssociation[{rest}]|>;
AsAssociation[stuff___] := stuff;
core /. List -> AsAssociation

When run it, It just gives me the Head of Sequence; running as AsAssociation@core, it gives my data back. Yes, recursion would be needed.

POSTED BY: Andrew Meit
Posted 3 years ago

Okay, after trying to infer what you're doing, it looks like one of my assumptions was wrong. You actually want nested associations. That wasn't shown in your original question.

Try something like this:

AsAssociation[list_List /; FreeQ[list, List, {2}]] := list;
AsAssociation[{k_, rest_}] := <|k -> AsAssociation[{rest}]|>;
AsAssociation[stuff___] := stuff;

AsAssociation uses recursion. If it is passed a list with no nested lists, it returns the list. If it is passed a list with nested lists, it creates an association. Otherwise it returns the argument unchanged. This function is still making some assumptions about the structure of your data, so I don't really know if it'll work, but maybe it's enough to get you closer.

POSTED BY: Eric Rimbey
Posted 3 years ago

Well, I don't know how to reproduce the problem you describe. Your sample data has a stray backslash in it, so I don't know what it's actually supposed to look like. When I remove the backslash and run my AsRule function on it, I don't have any problems. Your modified AsRule function has syntax problems, specifically it's missing the pattern stuff on the left hand side. Trying to use it exactly as is doesn't work at all, so I'm assuming there is a copy-paste error there. So, the upshot is that I don't have enough information to know what is going wrong in your case.

Sidenote, some your variable names are amusing!

POSTED BY: Eric Rimbey
Posted 3 years ago

Thank you! And learned more! However...

Some changes to get me closer to my goal:

AsRule[k_String, rest__] := k -> <|rest|>; AsRule[stuff___] := {stuff}
coreAss = <|core /. List -> AsRule|>;

But.. at the inner most the structure I get this

Association["x", "y", "v", "z", "a", "b", "c", "i", "k", "m", "n", "t"] 

should be

{"x", "y", "v", "z", "a", "b", "c", "i", "k", "m", "n", "t"}

From using this expression:

coreAss["Language"]["Variables"]["Standard Symbols"]

Hope am making sense.

My clumsy code was good but not the answer I want:

mkAsstemp[l_List] :=   (temp = Join[{{First@l}}, Rest@l];   
AssociationThread[First@# & /@ temp, Rest@# & /@ temp]);

======

The sample data, which is vastly larger, am using:

{"Language", {"Variables", {"TypeSet", 
   "\[SelectionPlaceholder]=\[Placeholder]", 
   "\[Placeholder]=\[SelectionPlaceholder]", 
   "\[SelectionPlaceholder]=\[Placeholder]=\[Placeholder]", 
   "\[SelectionPlaceholder]+=", "\[SelectionPlaceholder]-=", 
   "\[SelectionPlaceholder]/=", "\[SelectionPlaceholder]*=", 
   "\[SelectionPlaceholder]/:\[Placeholder]:=\[Placeholder]"}, \
{"Standard Symbols", "x", "y", "v", "z", "a", "b", "c", "i", "k", "m",
    "n", "t"}, {"Creating Varibles", 
   "Set[\[SelectionPlaceholder],\[Placeholder]]", 
   "SetDelayed[\[SelectionPlaceholder],\[Placeholder]]", 
   "SetDelayed[Condition[\[SelectionPlaceholder],\[Placeholder]]]", 
   "Unset[\[SelectionPlaceholder]]", 
   "With[{\[SelectionPlaceholder]},\[Placeholder]]", 
   "Block[{\[SelectionPlaceholder]},\[Placeholder]]", 
   "Unique[\[SelectionPlaceholder]]"}, {"Editing Variables", 
   "Clear[\[SelectionPlaceholder]]", 
   "ClearAll[\[SelectionPlaceholder]]", 
   "Remove[\[SelectionPlaceholder]]", 
   "AppendTo[\[SelectionPlaceholder],\[Placeholder]]", 
   "PrependTo[\[SelectionPlaceholder],]"}, {"Variable Basic Math", 
   "AddTo[\[SelectionPlaceholder]]", 
   "SubtractFrom[\[SelectionPlaceholder]]", 
   "DivideBy[\[SelectionPlaceholder]]", 
   "TimesBy[\[SelectionPlaceholder]]"}}}
POSTED BY: Andrew Meit
Posted 3 years ago

I'm making some assumptions:

  • The structure could be more complicated than what you've shown, in particular it could be more nested
  • You only want a list transformed if the first element is a string, otherwise you want to leave it as a list
  • The only Association that should be generated is the outermost one

You could define something like this:

AsRule[k_String, rest__] := k -> {rest};
AsRule[stuff___] := {stuff}

Then do a replace:

data /. List -> AsRule

Then just wrap the result in Association.

POSTED BY: Eric Rimbey
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract