Assuming a simple List
of Rule
s, e.g.
rules = {
a -> 1,
b -> 2,
c -> 3,
d -> 1,
e -> 4,
f -> 1
};
The following function allows one to get various amounts of key(s) associated with the specified value, using familiar list operators First
, Most
, Rest
, and Last
. One can also specify All
(typically an option) to get All keys associated with value. In addition, one can specify which key they want. The code is at the bottom of this post.
Examples
Using the rules defined above:
Default: return first instance of a key associated with the value
KeyFromValue[rules, 1]
(*a*)
Playing around with the option "Which"
:
KeyFromValue[rules, 1, "Which" -> Last]
(*f*)
KeyFromValue[rules, 1, "Which" -> All]
(*{a, d, f}*)
KeyFromValue[rules, 1, "Which" -> Most]
(*{a, d}*)
KeyFromValue[rules, 1, "Which" -> 2]
(*d*)
There is some limited error handling:
KeyFromValue[rules, 1, "Which" -> 5]
Asked for 5th instance of 1.
Only 3 instances found.
Out: {}
KeyFromValue[rules, 10]
Nothing found
Out: {}
Update
Added alternative definition to handle association:
assoc = <|a -> 1, b -> 2, c -> 3, d -> 1, e -> 4, f -> 1|>;
KeyFromValue[rules, 1]
KeyFromValue[assoc, 1]
KeyFromValue[rules, 1, "Which" -> Most]
KeyFromValue[assoc, 1, "Which" -> Most]
a
a
{a, d}
{a, d}
Code
I'm not claiming this is the most efficient means of doing so, but it does serve its purpose. Kudos to anyone who wants to abstract this for any list of rules.
Options[KeyFromValue] = {"Which" -> 1, "Verbose" -> False};
KeyFromValue[association_List, value_, OptionsPattern[]] :=
Module[
{found = First /@ Position[association, value]},
(*If that value is not found*)
If[found == {},
(*Return empty List*)
If[OptionValue[KeyFromValue, "Verbose"], Print["Nothing found"];]
Return[{}],
(*Else rename the position wanted as pos*)
With[{pos = OptionValue[KeyFromValue, "Which"]},
(*If pos is a function that returns an unwrapped singular value*)
If[MemberQ[{First, Last}, pos],
(*Apply the function. Return it.*)
Return[First@association[[#]] &@(pos@found)],
(*If pos is a function that returns a List*)
If[MemberQ[{Most, Rest}, pos],
(*Apply the function. Return it.*)
Return[First /@ (association[[#]] & /@ (pos@found))],
(*If pos is All (technically not a function)*)
If[MemberQ[{All}, pos],
(*Given them everything found*)
Return[First /@ (association[[#]] & /@ (found))],
(*Else, check to see if position valid.*)
If[pos <= Length@found,
(*If it is, return desired value.*)
Return[First@association[[found[[pos]]]]],
(*Else notify user and return {}.*)
If[OptionValue[KeyFromValue, "Verbose"],
Print["Asked for " <> ToString@pos <> "th instance of " <>
ToString@value <> ".\nOnly " <>
ToString[Length@found] " instances found."]];
Return[{}];
]
]
]
]
]
]
]
Options[KeyFromValue] = {"Which" -> 1, "Verbose" -> False};
KeyFromValue[association_Association, value_, OptionsPattern[]] :=
Module[
{found = First /@ First /@ Position[association, value]},
(*If that value is not found*)
If[found == {},
(*Return Missing List*)
If[OptionValue[KeyFromValue, "Verbose"], Print["Nothing found"];];
Return[Missing];
];
(*Else rename the position wanted as pos*)
With[{pos = OptionValue[KeyFromValue, "Which"]},
(*If pos is a function that returns an unwrapped singular value*)
If[MemberQ[{First, Last, Most, Rest}, pos],
(*Apply the function. Return it.*)
Return[(pos@found)],
(*If pos is All (technically not a function)*)
If[MemberQ[{All}, pos],
(*Given them everything found*)
Return[(found)],
(*Else, check to see if position valid.*)
If[pos <= Length@found,
(*If it is, return desired value.*)
Return[found[[pos]]],
(*Else notify user and return {}.*)
If[OptionValue[KeyFromValue, "Verbose"],
Print["Asked for " <> ToString@pos <> "th instance of " <>
ToString@value <> ".\nOnly " <>
ToString[Length@found] " instances found."]];
Return[{}];
]
]
]
]
]
Association
instead of aList
if your keys in eachList
are unique. Then you could just usePosition
. $\endgroup$