# 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 ... – Szabolcs Jul 20 '15 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 ==? – Szabolcs Jul 20 '15 at 12:07
• @szabolcs To catch cases where the value in one of the association keys is an undefined symbol? – Sjoerd C. de Vries Jul 20 '15 at 12:10
• Yes. That is what I meant. – Szabolcs Jul 20 '15 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. – Sjoerd C. de Vries Jul 20 '15 at 12:13
• @PatrickStevens apparently a fixed bug; see: (88165) – Mr.Wizard Jul 20 '15 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? – Patrick Stevens Jul 20 '15 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. – Mr.Wizard Jul 20 '15 at 15:59
• @Mr.Wizard I'm looking into why Union and Intersection are seemingly inconsistent on Association. – Stefan R Jul 20 '15 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. – Mr.Wizard Jul 20 '15 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 – alancalvitti Jul 20 '15 at 17:37