9
$\begingroup$

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

$\endgroup$
2
  • 6
    $\begingroup$ 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. $\endgroup$ Oct 8, 2014 at 11:47
  • 1
    $\begingroup$ In 10.4 you can match within Associations. $\endgroup$
    – masterxilo
    Jun 28, 2016 at 21:45

4 Answers 4

13
$\begingroup$

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 *)
$\endgroup$
2
  • $\begingroup$ The pattern should be assoc_Association /; MatchQ[Values[assoc], {__Association}], I believe; the current form will match <|1 -> <|"a" -> 3, "b" -> 4|>, 2 -> 5|>, which I believe is not wanted. $\endgroup$ Jun 4, 2016 at 0:01
  • $\begingroup$ @J.M. You may be right, but the question does not give enough information to be sure. $\endgroup$ Jun 4, 2016 at 8:43
6
$\begingroup$

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|>|>}  *)
$\endgroup$
4
  • $\begingroup$ It will also match <|b -> <|1 -> 1, 2 -> 2|>, c -> 1|> which is not nested association in this context. $\endgroup$
    – Kuba
    Jun 3, 2016 at 5:52
  • $\begingroup$ So he wants a pattern that matches associations where all keys are associations, right? $\endgroup$
    – M.R.
    Jun 3, 2016 at 19:09
  • $\begingroup$ I think so, but I'm not 100% sure :-/ $\endgroup$
    – Kuba
    Jun 3, 2016 at 19:17
  • $\begingroup$ @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. $\endgroup$ Jan 9, 2017 at 19:47
4
$\begingroup$

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
$\endgroup$
0
$\begingroup$

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} *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.