# How to make Cases work with associations?

Consider the following association of associations:

assoc = <|
{10,69}-><|84->1,88->2,110->1,118->4,108->1,114->8,78->2,112->1|>,
{69,84}-><|89->1,79->1,85->1,46->4,73->5,84->5,32->10,72->4,44->2,67->1,65->1,39->1,76->1,87->1|>,
{84,89}-><|77->1,69->1,32->1,46->1|>,
{89,77}-><|79->1|>,
{77,79}-><|76->1,82->8,85->5,78->4,68->1,32->1,44->2,41->4,69->1,86->2,75->1|>
{79,76}-><|79->3,76->8,89->1,68->8,65->3,78->1,69->1,73->10,85->1,83->1|>,
{76,79}-><|71->3,45->1,82->34,83->2,66->4,65->1,67->2,78->7,79->3,84->1,85->1,87->7|>,
{79,71}-><|89->3,82->2|>,
{71,89}-><|46->2,32->1|>,
{89,46}-><|10->8,34->1,41->1|>
|>


Why does Cases[Length /@ assoc // Normal, (key_List -> val_) :> key /; val == 1] work (it returns {{89, 77}}) while Cases[Length /@ assoc, (key_List -> val_) :> key /; val == 1] doesn't?

Cases has been overloaded for Association. Consider this example,

Cases[<|1 -> a, 2 -> "b", 3 -> "c"|>, _String]
(* {"b", "c"} *)


The keys are lost here, and so the RuleDelayed has no effect. However, Select returns an Association, even though it applies the predicate only to the values,

Select[<|1 -> a, 2 -> "b", 3 -> "c"|>, StringQ]
(* <|2 -> "b", 3 -> "c"|> *)


For the example in the OP, we can use Select, and then use Keys on the result,

Keys@Select[assoc, Length[#] == 1 &]
(* {{89, 77}} *)


edit:

You might think that KeyValuePattern is the right way to go here, but be aware that Cases is still going to match it only to the values:

Cases[assoc,
KeyValuePattern[key_ -> x_ /; Length[x] == 1] :> key]
(* {} *)


A workaround for this would be to wrap the Association in a List,

Cases[{assoc},
KeyValuePattern[key_ -> x_ /; Length[x] == 1] :> key]
(* {{89, 77}} *)


I think it would be useful to have a KeyValueCases for something like this.

• It was exactly my failure to work something out using KeyValuePattern that prompted this question; thanks Jan 15, 2018 at 18:27