4
$\begingroup$

So I have a list somewhat like this:

{
 {"name" -> "bob", "age" -> "20", "phone" -> "123456"},
 {"name" -> "Fred", "age" -> "40", "phone" -> "098765"}
} 

At the moment I am doing the following to pull out the related item ( y is the list).

pos = First[First[Position[y, "Fred"]]]
z = Part[y, pos]

This returns:

{"name" -> "Fred", "age" -> "40", "phone" -> "098765"}

While "Fred" won't show up in other fields, I'm not overly happy with this.

I was wondering if there is a more elegant way to find an array item based on the value of a certain field within that array?

$\endgroup$
3
  • $\begingroup$ @Xavier, looks like an answer to me. $\endgroup$ Oct 17, 2015 at 16:47
  • $\begingroup$ @Xavier Shape it in an answer and I'll vote on it. I tried that snippet you posted and it comes back with {} . I changed list to y. $\endgroup$ Oct 17, 2015 at 16:56
  • $\begingroup$ Possibly a list of associations would be more appropriate in your application than a list of rules, i.e. list = { <| "name" -> "bob", "age" -> "20", "phone" -> "123456" |>, <| "name" -> "Fred", "age" -> "40", "phone" -> "098765" |> } Then you can do things like list[[1]]["name"] and Select[list, #["name"] == "bob" &] $\endgroup$
    – Axel Boldt
    Oct 18, 2015 at 0:17

3 Answers 3

5
$\begingroup$

Comment posted as an answer, as suggested.


Notation

list = {
        {"name" -> "bob", "age" -> "20", "phone" -> "123456"},
        {"name" -> "Fred", "age" -> "40", "phone" -> "098765"}
       }

Possible solutions

If you are interested in getting z only, you can use

Cases[list, {_ -> "Fred", __}]

provided that the structure of all your sublists is the same as what you wrote. Alternatively, the function Select can be considered

Select[list, MatchQ[#, {_ -> "Fred", __}] &]

Those will give you all sublists where the name Fred occurs. In case there is only one item of this form, you will end up with {z} rather than z. A workaround would be

FirstCase[list, {_ -> "Fred", __}]

or

SelectFirst[list, MatchQ[#, {_ -> "Fred", __}] &]

Update

Following OP's comment, for a list of different structure one can use

 Cases[list, {___, "name" -> "Fred", ___}]

or

Select[list, MatchQ[#, {___, "name" -> "Fred", ___}] &]
$\endgroup$
5
  • 2
    $\begingroup$ Select[list, ! FreeQ[#, "Fred"] &][[1]] $\endgroup$
    – Bob Hanlon
    Oct 17, 2015 at 17:15
  • $\begingroup$ @Xavier. They work for the example, but if you change the fields position they don't appear to always works. :-/ Bob's work for say phone number, but you haven't specified an explicit field. So there is chance another field could match. $\endgroup$ Oct 17, 2015 at 17:25
  • 1
    $\begingroup$ Although not the exact answer helped me find the answer: Select[list, ! FreeQ[#, "name" -> "Fred"] &][[1]] $\endgroup$ Oct 17, 2015 at 17:30
  • $\begingroup$ @SimonO'Doherty See updated answer. $\endgroup$
    – user31159
    Oct 17, 2015 at 17:38
  • $\begingroup$ perfect! :) Thanks. $\endgroup$ Oct 17, 2015 at 17:38
7
$\begingroup$

The question is answered, but... one can also use a dataset to retrieve the information

{
 {"name" -> "bob", "age" -> "20", "phone" -> "123456"},
 {"name" -> "Fred", "age" -> "40", "phone" -> "098765"}
} 

then

ds = Dataset@(Association /@ input)

Retrieve information:

Select[ds, #name == "Fred" &]

result:

enter image description here

$\endgroup$
4
  • $\begingroup$ I was hoping someone would post an Association answer. This is in my opinion the most natural way to do this sort of thing. $\endgroup$
    – march
    Oct 17, 2015 at 20:33
  • $\begingroup$ I've only recently started using associations, but I have been very impressed with its utility as a data structure. $\endgroup$ Oct 17, 2015 at 20:56
  • 1
    $\begingroup$ Or ds[Select[#name == "Fred" &]]. $\endgroup$
    – Karsten 7.
    Oct 17, 2015 at 21:49
  • $\begingroup$ @Karsten7.: Indeed, this (your comment) is the way I use the Select command most offen ;-) $\endgroup$
    – mgamer
    Oct 18, 2015 at 9:06
4
$\begingroup$

This is a very natural solution that works in all versions of Mathematica:

x = {{"name" -> "bob", "age" -> "20", "phone" -> "123456"}, {"name" -> "Fred", "age" -> "40", "phone" -> "098765"}};

y = ("name" /. #) -> # & /@ x;

"Fred" /. y
(* Out: {"name" -> "Fred", "age" -> "40", "phone" -> "098765"} *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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