4
$\begingroup$

Suppose I have a table like the following (This example is simplified, actual table is much larger), it is read from external files:

table = {{1, A, x, y},
         {1, B, z, w},
         {2, A, v, u},
         {2, B, t, s}};

header = {i, j, g, h};

The third and fourth column are the actual content of my table, say their headers are g and h, and the first and second column are like indices for each row.

The output I am looking for is

tree = <|1 -> <|A -> <|g -> x, h -> y|>,
                B -> <|g -> z, h -> w|>|>,
         2 -> <|A -> <|g -> v, h -> u|>,
                B -> <|g -> t, h -> s|>|>|>;

The reason behind this is that a regular table of association (give the first and second column header i and j) takes too long to find the rows using Select (8800 sec for the actual table). This might speed up things quite a bit because it is a tree structure in nature. So if I want to access one particular row, I just use the command tree[1][A] or tree[1][A][g] to get the content of the first row.

So how would you code this into Mathematica? I am open to completely different approaches as well. Thanks!

$\endgroup$
  • $\begingroup$ So may I ask why the last level shouldn't be <|g->h|> but <g->x,h->y>? I suppose in your real situation the list is quite large, so It's crucial to know about why you choose this way, or our answer will be useless for your real application. $\endgroup$ – Wjx Aug 12 '16 at 2:54
  • $\begingroup$ Is your table sorted by first element? $\endgroup$ – JungHwan Min Aug 12 '16 at 3:17
  • $\begingroup$ Closely related: Reshaping associations, generalization of GroupBy and How to make use of Associations? $\endgroup$ – Kuba Aug 12 '16 at 5:51
  • $\begingroup$ @Wjx g and h are just indices, the real data is x and y. $\endgroup$ – Kaa1el Aug 12 '16 at 7:24
  • $\begingroup$ @JHM sorting is irrelevant in my application. $\endgroup$ – Kaa1el Aug 12 '16 at 7:25
4
$\begingroup$
  1. less general

    # -> <|#2 -> <|g -> #3, h -> #4|>|> & @@@ table // Merge[Association]
    
       <|
         1 -> <|A -> <|g -> 5, h -> y|>, B -> <|g -> z, h -> w|>|>, 
         2 -> <|A -> <|g -> v, h -> u|>, B -> <|g -> t, h -> s|>|>
    |>
    
  2. more general

    newAsso = AssociationThread[header, #] & /@ table
    
     {<|i -> 1, j -> A, g -> x, h -> y|>, 
      <|i -> 1, j -> B, g -> z, h -> w|>, 
      <|i -> 2, j -> A, g -> v, h -> u|>, 
       <|i -> 2, j -> B,  g -> t, h -> s|>}
    
     nested = GroupBy[newAsso, {Key@i, Key@j}, Map[KeyDrop[{i, j}]@*First]]
    
    <|
       1 -> <|A -> <|g -> x, h -> y|>, B -> <|g -> z, h -> w|>|>, 
       2 -> <|A -> <|g -> v, h -> u|>, B -> <|g -> t, h -> s|>|>
    |>
    

    nested[2, A]

    <|g -> v, h -> u|>
    
  3. alternatively

    GroupBy[
       table, 
       {#[[1]] &, #[[2]] & -> (AssociationThread[{g, h}, #[[3 ;;]]] &)}, 
       Map[First]
    ]
    
  4. or

     GroupBy[
        table, 
        {First -> Rest, First -> (AssociationThread[{g, h}, Rest[#]] &)}, 
        Map[First]
     ]
    
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.