Welcome, guest | Sign In | My Account | Store | Cart

Find all occurencies of given map in map list, yielding index of first match and subsequently indexes of all other found. All maps in list have the same structure, pattern for search can have the same structure or less keys.

Python, 75 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def find_map_gen(main_list,pattern):
   """each call of next() method of this generator
   yields next index of main_list where pattern matches main_list[index]
   or raise StopIteration if there isn't next match
   
   main_list elements and pattern are maps with identical structure,
   pattern can have less keys
   
   meaning of 'match' need to be defined on your match function
   which have to compare value of pattern[key] with each element[key]
   and return list of True|False values for each element of main_list.
   It's up to you if match function does exact matching or for ex.
   for strings values pattern matching. All match fnc have to do is
   return for given key the list [first_elem_matches, second_elem_don't, ...]
   in True|False form, of course.

   """
   def varzip(a):
     return zip(*a)
 
   match_key_list = []
   true_tuple = tuple([True]*len(pattern))
   for key in pattern.keys():
      match_key_list.append(match(key,pattern,main_list))
   match_index_list = varzip(match_key_list)
   find_list = [true_tuple==x for x in match_index_list]
   for i,x in enumerate(find_list):
      if x: yield i


# example of use

find_gen = find_map_gen(my_list,pattern)
try:
   id = find_gen.next()
   print 'found %s -th record' % id+1
except StopIteration:
   print 'no more'

# very very simple example

>>> def match(key,pattern,list):
...   pattern_val = pattern[key]
...   return [pattern_val == elem[key] for elem in list]

>>> my_list = [{'a':1,'b':2, 'c':3}, {'a':1, 'b':6, 'c':4}]
>>> # all elems where a is 1
>>> pattern = {'a':1}
>>> find_gen = find_map_gen(my_list,pattern)
>>> print find_gen.next()
0                                # my_list[0] matches
>>> print find_gen.next()
1                                # my_list[1] matches too
>>> print find_gen.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
StopIteration                    # no more matches
>>>
>>> # all elems where a is 1 and c is 4
>>> pattern = {'a':1, 'c':4}
>>> find_gen = find_map_gen(my_list,pattern)
>>> print find_gen.next()
1                                # my_list[1] matches
>>> print find_gen.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
StopIteration                    # no more matches
>>>
>>> all elems with b is 7
>>>  pattern = {'b':7}
>>> find_gen = find_map_gen(my_list,pattern)
>>> print find_gen.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
StopIteration                    # no matches found

It's useful for list of personal contact (as example) with structure {'name':'Joe','surname':'Doe','phone':'123', and so on} and a question: find me 'Joe', no this isn't right one, find me next one.

I used this in GUI application where creation of find_gen and first call to its next() method is binding to dialog window asking for pattern values, return value is used for highlighting row in grid, subsequent calls are binded to F3 key and higlights another row in grid, StopIteration exception shows info 'No more matches' (Yes, match function in this case is a little bit complicated one :)

Created by Pietro Bernardi on Sun, 19 Aug 2007 (PSF)
Python recipes (4591)
Pietro Bernardi's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks