30

I have a dictionary with key-value pair. My value contains strings. How can I search if a specific string exists in the dictionary and return the key that correspond to the key that contains the value.

Let's say I want to search if the string 'Mary' exists in the dictionary value and get the key that contains it. This is what I tried but obviously it doesn't work that way.

#Just an example how the dictionary may look like
myDict = {'age': ['12'], 'address': ['34 Main Street, 212 First Avenue'],
          'firstName': ['Alan', 'Mary-Ann'], 'lastName': ['Stone', 'Lee']}

#Checking if string 'Mary' exists in dictionary value
print 'Mary' in myDict.values()

Is there a better way to do this since I may want to look for a substring of the value stored ('Mary' is a substring of the value 'Mary-Ann').

11 Answers 11

43

You can do it like this:

#Just an example how the dictionary may look like
myDict = {'age': ['12'], 'address': ['34 Main Street, 212 First Avenue'],
      'firstName': ['Alan', 'Mary-Ann'], 'lastName': ['Stone', 'Lee']}

def search(values, searchFor):
    for k in values:
        for v in values[k]:
            if searchFor in v:
                return k
    return None

#Checking if string 'Mary' exists in dictionary value
print search(myDict, 'Mary') #prints firstName
3
  • 1
    what will be performance issue in this, if suppose I have 1 million records and I'm implementing this for Auto complete search. Commented May 29, 2015 at 8:38
  • 1
    @Unknown You should definitely not do this for your case. You need to index the values in a separate reverse lookup dictionary.
    – wisbucky
    Commented Aug 18, 2015 at 0:14
  • 7
    Alternatively, if you know the dictionary is huge, you could convert it to JSON and perform a regex search such as pattern = r'\w+(?=": [\S\s][^:]+{})'.format(search_text) to get the key. It won't be faster for smaller dictionaries, but it will be for larger ones, in particular when the data is in the worst case position
    – Erik
    Commented Jan 6, 2017 at 21:47
23

I am a bit late, but another way is to use list comprehension and the any function, that takes an iterable and returns True whenever one element is True :

# Checking if string 'Mary' exists in the lists of the dictionary values
print any(any('Mary' in s for s in subList) for subList in myDict.values())

If you wanna count the number of element that have "Mary" in them, you can use sum():

# Number of sublists containing 'Mary'
print sum(any('Mary' in s for s in subList) for subList in myDict.values())

# Number of strings containing 'Mary'
print sum(sum('Mary' in s for s in subList) for subList in myDict.values())

From these methods, we can easily make functions to check which are the keys or values matching.

To get the keys containing 'Mary':

def matchingKeys(dictionary, searchString):
    return [key for key,val in dictionary.items() if any(searchString in s for s in val)]

To get the sublists:

def matchingValues(dictionary, searchString):
    return [val for val in dictionary.values() if any(searchString in s for s in val)]

To get the strings:

def matchingValues(dictionary, searchString):
    return [s for s i for val in dictionary.values() if any(searchString in s for s in val)]

To get both:

def matchingElements(dictionary, searchString):
    return {key:val for key,val in dictionary.items() if any(searchString in s for s in val)}

And if you want to get only the strings containing "Mary", you can do a double list comprehension :

def matchingStrings(dictionary, searchString):
    return [s for val in dictionary.values() for s in val if searchString in s]
6
  • 1
    For getting the keys, based on the dictionary used by the user in the question it returns this error message <ipython-input-7-b5d6370c2444> in <genexpr>(.0) ----> 1 print (sum(1 for key,val in myDict if 'Mary' in val) > 0) ValueError: too many values to unpack (expected 2) and is the same for the matchingKeys function <ipython-input-2-65db50c6e286> in <listcomp>(.0) 1 def matchingKeys(dictionary, searchString): ----> 2 return [key for key,val in dictionary if searchString in val] ValueError: too many values to unpack (expected 2) Commented Feb 7, 2021 at 15:55
  • 1
    @AndreaCiufo Oops my bad, I forgot to use the method dict.items. I wanted to give the concept, the idea of using one line list comprehension but by reading it all over again, I realize I have made many mistakes
    – Naeio
    Commented Feb 8, 2021 at 9:50
  • 1
    yep this happens because there is a list of strings associated with keys and not a single string :) Commented Feb 8, 2021 at 15:16
  • 1
    Exactly, and I forgot the dict.items :) IDK what I was thinking about when writing my answer, I guess I went too fast
    – Naeio
    Commented Feb 11, 2021 at 23:53
  • 1
    How might someone search multiple strings? using this approach Commented Apr 1, 2021 at 23:29
13

Klaus solution has less overhead, on the other hand this one may be more readable

myDict = {'age': ['12'], 'address': ['34 Main Street, 212 First Avenue'],
          'firstName': ['Alan', 'Mary-Ann'], 'lastName': ['Stone', 'Lee']}

def search(myDict, lookup):
    for key, value in myDict.items():
        for v in value:
            if lookup in v:
                return key

search(myDict, 'Mary')
4
import re
for i in range(len(myDict.values())):
     for j in range(len(myDict.values()[i])):
             match=re.search(r'Mary', myDict.values()[i][j])
             if match:
                     print match.group() #Mary
                     print myDict.keys()[i] #firstName
                     print myDict.values()[i][j] #Mary-Ann
2
>>> myDict
{'lastName': ['Stone', 'Lee'], 'age': ['12'], 'firstName': ['Alan', 'Mary-Ann'],
 'address': ['34 Main Street, 212 First Avenue']}

>>> Set = set()

>>> not ['' for Key, Values in myDict.items() for Value in Values if 'Mary' in Value and Set.add(Key)] and list(Set)
['firstName']
2

For me, this also worked:

def search(myDict, search1):
    search.a=[]
    for key, value in myDict.items():
        if search1 in value:
            search.a.append(key)

search(myDict, 'anyName')
print(search.a)
  • search.a makes the list a globally available
  • if a match of the substring is found in any value, the key of that value will be appended to a
4
  • I just learned, that search.a is not a smart way to make a globally available. currently working it out, this may help: python-textbok.readthedocs.io/en/1.0/Variables_and_Scope.html
    – Shushiro
    Commented Nov 1, 2017 at 11:36
  • solution found via:stackoverflow.com/questions/7129285/…
    – Shushiro
    Commented Nov 1, 2017 at 11:43
  • def search(myDict, search1): a=[] for key, value in myDict.items(): if search1 in value: a.append(key) return a x=search(myDict, 'anyName') print(str(x))
    – Shushiro
    Commented Nov 1, 2017 at 11:48
  • def search(myDict, search1): a=[] for key, value in myDict.items(): if search1 in value: a.append(key) return a x=search(myDict, 'anyName') print(str(x))
    – Shushiro
    Commented Nov 1, 2017 at 11:48
1

Following is one liner for accepted answer ... (for one line lovers ..)

def search_dict(my_dict,searchFor):
    s_val = [[ k if searchFor in v else None for v in my_dict[k]] for k in my_dict]    
    return s_val
5
  • 1
    Ah, gotcha. You could do it in one line like this: search_dict = lambda x, y: ((k if y in v else None for v in x[k]) for k in x) Commented Jul 7, 2018 at 17:46
  • I get an error list indices must be integers or slices, not list Commented Feb 7, 2021 at 12:53
  • @AndreaCiufo give ur code .. i think you dict contains multiple values in a single key.. Commented Feb 10, 2021 at 9:19
  • I used the question code, and actually contains a list of strings and was similar to @Nei oversight here :) Commented Feb 10, 2021 at 10:54
  • @AndreaCiufo is the problem fixed now ? Commented Mar 5, 2021 at 2:45
1

To provide a more general solution for others using this post to do similar or more complex python dictionary searches: you can use dictpy

import dictpy

myDict = {'age': ['12'], 'address': ['34 Main Street, 212 First Avenue'],
          'firstName': ['Alan', 'Mary-Ann'], 'lastName': ['Stone', 'Lee']}

search = dictpy.DictSearch(data=myDict, target='Mary-Ann')
print(search.result)   # prints -> [firstName.1, 'Mary-Ann']  

The first entry in the list is the target location: dictionary key "firstName" and position 1 in the list. The second entry is the search return object.

The benefit of dictpy is it can find multiple 'Mary-Ann' and not just the first one. It tells you the location in which it found it, and you can search more complex dictionaries (more levels of nesting) and change what the return object is.

0
import re
for i in range(len(myDict.values())):
    for j in range(len(myDict.values()[i])):
         match=re.search(r'Mary', myDict.values()[i][j])
         if match:
                 print match.group() #Mary
                 print myDict.keys()[i] #firstName
                 print myDict.values()[i][j] #Mary-Ann
0
def search(myDict, lookup):
    a=[]
    for key, value in myDict.items():
        for v in value:
            if lookup in v:
                 a.append(key)
    a=list(set(a))
    return a

if the research involves more keys maybe you should create a list with all the keys

-3

import json 'mtach' in json.dumps(myDict) is true if found

1

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.