# Is there an idiomatic way to determine whether an Association is a subset of another?

I would like a way to tell if every key-value pair of an Association is contained in another. For instance, f[<|c -> 1, d -> 2|>, <|a -> 1|>] should evaluate False, but f[<|a -> 1, d -> 2|>, <|a -> 1|>] should evaluate True.

The functions SubsetQ or ContainsAll ought intuitively to do what I want, but they turn out only to operate on the values of an Association, not the key-value pairs.

Currently the best I have is SubsetQ @@ Normal@*List@## &. Is there a nicer (preferably in-built) way to do it than that, preferably which doesn't involve casting the whole lot to Lists? It's the kind of thing I'd expect there to be a built-in function for, but for the life of me I can't find it.

• It may be possible to abuse JoinAcross for this purpose, but what you did with SubsetQ is so much more clear than that ... Jul 20, 2015 at 11:54

associationSubSetQ[x_Association, y_Association] :=
KeyIntersection[{y, x}][[2]] == y

associationSubSetQ[<|a -> 1, d -> 2|>, <|a -> 1|>]


True

associationSubSetQ[<|c -> 1, d -> 2|>, <|a -> 1|>]


False

## Alternative

Another method would be

associationSubSetQ[x_Association, y_Association] :=
Keys[#] === Values[#] &[KeyMap[x, y]]


This works because KeyMap maps x over the keys of y, which gets you

<|x[keyY1]->valueY1,x[keyY2]->valueY2 ...|>


which reduces to

<|valueY1->valueY1, valueY2->valueY2 ...|>


if and only if y is a subset of x (otherwise you get Missing in some positions).

The Keys[#] === Values[#] & part then checks whether the vector of keys equals the vector of values. This works because both Keys and Values keep the order of the keys and values, respectively.

• Shouldn't it be === instead of ==? Jul 20, 2015 at 12:07
• @szabolcs To catch cases where the value in one of the association keys is an undefined symbol? Jul 20, 2015 at 12:10
• Yes. That is what I meant. Jul 20, 2015 at 12:11
• Depends on what the OP wants it to do. If you leave it as is the answer may be <|a->1|>==<a->xyz|> which may or may not be what the OP wants. Jul 20, 2015 at 12:13
• @PatrickStevens apparently a fixed bug; see: (88165) Jul 20, 2015 at 16:46

This seems to work:

f = Complement[#2, #] == <||> &;

f[<|c -> 1, d -> 2|>, <|a -> 1|>]
f[<|a -> 1, d -> 2|>, <|a -> 1|>]

False

True

• Do you know of any reason why Complement should work on Associations in this way, Union does not, but Intersection does? Is there something special about Union? Jul 20, 2015 at 15:49
• @Patrick No, I think it is just the spotty implementation of these functions at this point. The developers are apparently being pushed to add more and more functionality with less and less of it actually being release-ready, which is makes me sad. Jul 20, 2015 at 15:59
• @Mr.Wizard I'm looking into why Union and Intersection are seemingly inconsistent on Association. Jul 20, 2015 at 17:12
• @Stefan Thank you. I much appreciate the work you are doing on these issues, I just wish you were getting more help. Jul 20, 2015 at 17:16
• @Mr.Wizard Tyte. Also look at reference.wolfram.com/language/ref/ContainsAll.html type functions which should but not yet have Key counterparts eghttp://mathematica.stackexchange.com/questions/59237/missing-keygroupby Jul 20, 2015 at 17:37

Slightly different from the other answers:

f[Association[args__], Association[args2__]] := ContainsAll[{args}, {args2}]

f[<|c -> 1, d -> 2|>, <|a -> 1|>]
(* Out: False *)

f[<|a -> 1, d -> 2|>, <|a -> 1|>]
(* Out: True *)