Message Boards Message Boards

2
|
6616 Views
|
7 Replies
|
7 Total Likes
View groups...
Share
Share this post:

Use a key collision function to combine results of JoinAcross[ ]?

Posted 8 years ago

In the Wolfram Language Documentation for JoinAcross, there is an example that uses a KeyCollisionFunction to change the keys (labels) that result from a join across operation:

in[]: JoinAcross[{<|a -> 1, b -> X|>}, {<|a -> 1, b -> Y|>}, 
 Key[a], "Inner", KeyCollisionFunction -> Function[x, {left[x], right[x]}]]

This produces:

out[]: {<|a -> 1, left[b] -> X, right[b] -> Y|>}

I have a similar problem, but I would like to Join two arrays (or associations) on Key A, and combine the values associated with Key B. That is...

in[]: JoinAcross[{<|a -> 1, b -> X|>}, {<|a -> 1, b -> Y|>}, 
 Key[a], "Inner",  KeyCollisionFunction -> SOME FUNCTION ]

To produce:

{<|a -> 1, b -> {X, Y}|>}

Note, instead of modifying the keys left[b] and right[b], we keep the original key b and combined the values from left and right, into a list associated with the original key b ->{X, Y}. It seems like there should be a straightforward way to do this, but I am not very handy with the syntax for pure functions. Can anyone explain how to do this?

POSTED BY: Caitlin Ramsey
7 Replies

I suppose a more general example is needed (this one doesn't need JoinAcross specific features) but here is something what may be good enough:

MapAt[First, Key[a]] @ Merge[Identity] @ {<|a -> 1, b -> X|>, <|a -> 1, b -> Y|>}
<|a -> 1, b -> {X, Y}|>
POSTED BY: Kuba Podkalicki

Nice solution for the simple case, however this does not work when there are two different 'a' matches:

MapAt[First, Key[a]]@
 Merge[Identity]@{<|a -> 1, b -> 1|>, <|a -> 1, b -> 2|>, <|a -> 2, 
    b -> 3|>, <|a -> 2, b -> 4|>}

Furthermore you don't have a set of 'left' and 'right' associations. I was playing with Merge and GroupBy, but these don't perform a 'join', which is what she wants (I think)... Some more elaborate example would be necessary to see what is wanted...

POSTED BY: Sander Huisman

Yes, I agree it is a simple code, we need a better example to test. From what OP has already said I don't know if we have 2 lists of associations (as JoinAccros requires) or it is just a single list that is supposed to be merged in a fancy way.

In the latter case we can adjust my simple approach:

list = {<|a -> 1, b -> 1|>, <|a -> 1, b -> 2|>, <|a -> 2, b -> 3|>, <| a -> 2, b -> 4|>, <|a -> 3, b -> 4|> (*unmatched addition*)}

Values @ GroupBy[list, Key[a], MapAt[First, Key[a]] @* Merge[Identity]]

{<|a -> 1, b -> {1, 2}|>, <|a -> 2, b -> {3, 4}|>, <|a -> 3, b -> {4}|>}

For a->3 there isn't any mach, should b's value be wrapped with {}?, probably depends of OP's needs too.

Alternatively, the same code but with more readable operators order:

GroupBy[list, Key[a], Merge[Identity] /* MapAt[First, Key[a]] ] // Values
POSTED BY: Kuba Podkalicki

Nice! I agree, a more 'expanded' example and requirements would be needed to judge the OP's needs...

POSTED BY: Sander Huisman

Hi Caitlin,

I'm pretty sure JoinAcross can not do what you want 'out of the box'. However we can make a function that collects the left and right terms and forms a single key:

ClearAll[MergeLeftRight]
MergeLeftRight[assoc_Association]:=Module[{keys,new,newassoc},
    keys=Cases[Keys[assoc],left[_]|right[_]];
    keys=GatherBy[keys,First];
    new=(First[First[#]]->(assoc/@#))&/@keys;
    newassoc=assoc;
    KeyDropFrom[newassoc,Join@@keys];
    newassoc~Join~Association[new]
]

out=JoinAcross[{<|a->1,b->X,c->3|>,<|a->2,b->3|>},{<|a->1,b->Y,c->2|>,<|a->1,b->z,c->4|>,<|a->2,b->cc,c->1|>},Key[a],"Inner",KeyCollisionFunction->Function[x,{left[x],right[x]}]]
out//Column

out = MergeLeftRight/@out;
out // Column

Let me know if this is what you want...

POSTED BY: Sander Huisman
Posted 8 years ago

I do not always have exactly two, and they are part of many associations, with one, two, or more associations that match on Key a. I want to track more than b, but b happens to be the only one that has the form List. (The values associated with other keys would usually be individual strings.)

POSTED BY: Caitlin Ramsey

Do you explicitly always have two associations? Or is it part of many many associations? (first and second argument are now explicitly lists of length 1). And do you only want to track 'b' or more than one?

Depending on the answer you might want to look into Merge and GroupBy...

POSTED BY: Sander Huisman
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