9

Suppose I have Association

testAssoc=Association[a->Association[1->1,2->2],b->Association[1->1,2->2]]

which pattern match this Association?

PS: of course MatchQ[testAssoc, _Association] return true, but I want to match ONLY nested Associations

M.R.
  • 31,425
  • 8
  • 90
  • 281
molekyla777
  • 2,888
  • 1
  • 14
  • 28
  • 6
    An Association is an atom in Mathematica, so formally it has no deeper structure. It is not even an expression with head Association and some arguments; the command MatchQ[testAssoc, Association[___]] returns False. So I think the best you can do is first to use functions like Normal or Values: MatchQ[Values[testAssoc], {__Association}]] returns True. – Fred Simons Oct 08 '14 at 11:47
  • 1
    In 10.4 you can match within Associations. – masterxilo Jun 28 '16 at 21:45

4 Answers4

13

Currently pattern - matcher doesn' t go inside an Association, and _Association is an exception (head test). You can note, for example, that an Association is AtomQ (although this is only a consequence of that). So, if you want to use pure patterns, you're currently out of luck. But, you can use recursive patterns. In this case:

nestedAssocPattern = assoc_Association /; MemberQ[Values[assoc], _Association]

Now, you can test:

MatchQ[testAssoc, nestedAssocPattern]

(* True *)

MatchQ[<|1 -> 2|>, nestedAssocPattern]

(* False *)
Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
6

With 10.4 you can use KeyValuePattern, or you can do it directly with a condition.

This gives elements whose keys are Associations:

Cases[{<|a -> <|1 -> 1|>, b -> <|2 -> 2|>|>, <|a -> <|1 -> 1, 2 -> 2|>, c -> 4|>}, 
    x_Association /; Union[Head /@ Values@x] == {Association}, {1}]

(* {<|a -> <|1 -> 1|>, b -> <|2 -> 2|>|>}  *)
M.R.
  • 31,425
  • 8
  • 90
  • 281
  • It will also match <|b -> <|1 -> 1, 2 -> 2|>, c -> 1|> which is not nested association in this context. – Kuba Jun 03 '16 at 05:52
  • So he wants a pattern that matches associations where all keys are associations, right? – M.R. Jun 03 '16 at 19:09
  • I think so, but I'm not 100% sure :-/ – Kuba Jun 03 '16 at 19:17
  • @M.R., beware that KeyValuePattern only matches the first matching Key-Value rules in an Association and will not match subsequent ones. That behavior is at odds with replacement in Lists, eg if the Association is Normalized to a List. – alancalvitti Jan 09 '17 at 19:47
4

As already pointed out by others Association objects are presently not traversed by pattern matching.

See:

My interpretation of your question is that you want to test to see if all values in the top Association are themselves Associations, rather than testing if only one value is, which is what kguler and Leonid answered. Therefore I propose:

asc_Association /; MatchQ[Values[asc], {__Association}]

This checks that entire expression and all of its values are Associations.


One could almost use this Condition instead of MatchQ: AllTrue[asc, AssociationQ] except that:

AllTrue[<||>, AssociationQ]
True
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
0

Perhaps

foo=!FreeQ[#,_Association,1]&;

testAssoc=Association[a->Association[1->1,2->2],b->Association[1->1,2->2]];
testAssoc2=Association[a->aa,b->bb];
testAssoc3=List[a->Association[1->1,2->2],b->Association[1->1,2->2]];

foo/@{testAssoc,testAssoc2,testAssoc3}
(* {True, False, False} *)
kglr
  • 394,356
  • 18
  • 477
  • 896