If you only need to check keys that are starting with "seller_account", you don't need regex, just use startswith()
my_dict={'account_0':123445,'seller_account':454545,'seller_account_0':454676, 'seller_account_number':3433343}
for key, value in my_dict.iteritems(): # iter on both keys and values
if key.startswith('seller_account'):
print key, value
or in a one_liner way :
result = [(key, value) for key, value in my_dict.iteritems() if key.startswith("seller_account")]
NB: for a python 3.X use, replace iteritems() by items() and don't forget to add () for print.
If you only need to check keys that are starting with "seller_account", you don't need regex, just use startswith()
my_dict={'account_0':123445,'seller_account':454545,'seller_account_0':454676, 'seller_account_number':3433343}
for key, value in my_dict.iteritems(): # iter on both keys and values
if key.startswith('seller_account'):
print key, value
or in a one_liner way :
result = [(key, value) for key, value in my_dict.iteritems() if key.startswith("seller_account")]
NB: for a python 3.X use, replace iteritems() by items() and don't forget to add () for print.
You can solve this with dpath.
http://github.com/akesterson/dpath-python
dpath lets you search dictionaries with a glob syntax on the keys, and to filter the values. What you want is trivial:
$ easy_install dpath
>>> dpath.util.search(MY_DICT, 'seller_account*')
... That will return you a big merged dictionary of all the keys matching that glob. If you just want the paths and values:
$ easy_install dpath
>>> for (path, value) in dpath.util.search(MY_DICT, 'seller_account*', yielded=True):
>>> ... # do something with the path and value
python - Good and pythonic way to filter list of dictionaries with regular expressions - Stack Overflow
python - Remove dictionary values based on regex? - Stack Overflow
python - Filtering list of dictionaries by regex match - Stack Overflow
regular expression dictionary key search - Post.Byes - Bytes
I wouldn't try to make a function with all of these responsibilities. It will make testing extremely difficult. Instead I would use the simplest list comprehensions possible for each case:
import re
dic = (
{"name": "Kan", "number": "2ABC345", "year": 2000},
{"name": "Jhon", "number": "2TTC345", "year": 2001},
{"name": "Louise", "number": "2ABC366", "year": 2001},
{"name": "Kevin", "number": "2ABY000", "year": 2002},
)
# So let's say I want the year 2000
year_2000 = [d for d in dic if d["year"] == 2000]
# or the first letter in name be a k
name_k = [d for d in dic if d["name"].startswith("K")]
# or to see if the number starts with 2 and has 7 numbers
starts_2_digits_7 = [d for d in dic if re.match(r"^2\d{6}$", d["number"])]
Let's start from a remark that regular expressions operate on strings. So it is good that you corrected your dic so that each dictionary contains strings (initially year was a number).
The first correction that you should made is that re.compile(dic)
is wrong.
You can compile a pattern, not the dictionary.
And since you execute your pattern once only, there is no need to compile it in advance. It is simpler when you use just the pattern argument (a string).
Your function can be:
def func(dic, pat, key):
return list(filter(lambda x: re.search(pat, x[key]), dic))
When you want just to print what has been found, it is enough that the function returns the finding and when you call the function the result will be printed.
Try func(dic, '2000', 'year') and func(dic, '^K', 'name').
It should print just what you want.
But an attempt to run func(dic, '2\d{7}', 'number') will return []
(an empty list), since no number in your data sample contains 2
followed by 7 digits.
But you can e.g. run func(dic, '2A[A-Z]{2}', 'number'), i.e. find
dictionaries with number containing:
- '2A',
- and then 2 letters.
This time you will get:
[{'name': 'Kan', 'number': '2ABC345', 'year': '2000'},
{'name': 'Louise', 'number': '2ABC366', 'year': '2001'},
{'name': 'Kevin', 'number': '2ABY000', 'year': '2002'}]
Edit
If you have some elements of your dictionaries other that strings, you can convert them to a string in your function. Change your function to:
def func(dic, pat, key):
return list(filter(lambda x: re.search(pat, str(x[key])), dic))
and it will work also on non-string elements in your source dictionaries.
This should match all the keys in your example as well as your exception case:
new_dict = {k:dict1[k] for k in dict1 if re.match('[^\d\s]+\d{1,2}$', k)}
Using a new example dict with your exception in it:
>>> dict1 = {"key1": 2345, "key2": 356, "key3": 773, "key44": 88, "key333": 12, "key3X": 13, "hello13": 435, "hello4325": 345, "3hi33":3}
>>> new_dict = {k:dict1[k] for k in dict1 if re.match('[^\d\s]+\d{1,2}$', k)}
>>> print(new_dict)
{'hello13': 435, 'key44': 88, 'key3': 773, 'key2': 356, 'key1': 2345}
You can use a regex to match 3 letters, followed by one or two digits, followed directly by the end of the string ($):
>>> import re
>>> small_dict = {k:v for k,v in dict1.items() if re.match('[a-z]{3}\d{1,2}$',k, re.IGNORECASE)}
>>> small_dict
{'key44': 88, 'key3': 773, 'key1': 2345, 'key2': 356}
Note that re.match searches for the regex at the beginning of the string : "123key123" wouldn't match for example.
If there are exceptions, you could add them after having filtered the keys. If you want to do it in one go:
small_dict = {k:v for k,v in dict1.items() if re.match('[a-z]{3}\d{1,2}$',k, re.IGNORECASE) or k in ["hello12", "hello34"]}
IIUC, I might do do something like
allowed = [msg for msg in collected
if not any( dm.search(msg['service'])
for dm in denied_metrics) ]
For example:
>>> pprint.pprint(collected)
[{'denied': False, 'metric': 1.0, 'service': 'ab'},
{'denied': False, 'metric': 1.0, 'service': 'bc'},
{'denied': False, 'metric': 1.0, 'service': 'ca'},
{'denied': False, 'metric': 1.0, 'service': 'cb'},
{'denied': False, 'metric': 1.0, 'service': 'bc'}]
>>> denied_metrics = [re.compile("a"), re.compile("c$")]
>>> allowed = [msg for msg in collected
if not any(dm.search(msg['service'])
for dm in denied_metrics)]
>>> allowed
[{'metric': 1.0, 'service': 'cb', 'denied': False}]
Whether you want search or match depends upon your regexes, of course. [BTW, wouldn't 'denied_services' be a better name?]
You have an XY problem.
Here are two ways to delete elments of a list while iterating in it:
li = ['a',12,45,'h',56,'ju',0]
print li
for i in xrange(len(li)-1,-1,-1):
if isinstance(li[i],int):
del li[i]
print li
# prints ['a', 'h', 'ju']
.
li = ['a',12,45,'h',56,'ju',0]
L = len(li)
for i,x in enumerate(reversed(li),1):
if isinstance(x,str):
del li[L-i]
print li
# prints [12, 45, 56, 0]
In the last code reversed() returns an iterator, no new list has to be created.
Constructing a new dict:
dict_you_want = {key: old_dict[key] for key in your_keys}
Uses dictionary comprehension.
If you use a version which lacks them (ie Python 2.6 and earlier), make it dict((key, old_dict[key]) for ...). It's the same, though uglier.
Note that this, unlike jnnnnn's version, has stable performance (depends only on number of your_keys) for old_dicts of any size. Both in terms of speed and memory. Since this is a generator expression, it processes one item at a time, and it doesn't looks through all items of old_dict.
Removing everything in-place:
unwanted = set(old_dict) - set(your_keys)
for unwanted_key in unwanted: del your_dict[unwanted_key]
Slightly more elegant dict comprehension:
foodict = {k: v for k, v in mydict.items() if k.startswith('foo')}
You do not have to pass d.items() as an iterable to filter. Just pass the dict object (same as dict.keys()) and filter the content based on dict[key] with lambda expression as:
>>> number_key = {35135135: 5, 60103513: 3, 10981179: 2, 18637724 : 4}
>>> filter(lambda x: number_key[x]<=3, number_key)
[60103513, 10981179]
Alternatively, you may also use a list comprehension expression to filter your dictionary as:
>>> number_key = {35135135: 5, 60103513: 3, 10981179: 2, 18637724 : 4}
>>> [k for k, v in number_key.items() if v<= 3]
[60103513, 10981179]
Say I have a dictionary (in Python 3), that's like this:
fruits = {"red fruit":"apple", "yellow fruit":"banana", "green fruit":"kiwi"}
Then I have a text string like:
I have a red fruit, a carrot, a blueberry, a yellow fruit, two potatoes and three green fruits.
I want to be able to replace "red fruit" with "apple" and so on with the other phrases I use as keys in the dictionary. I realize I can loop through the dictionary with replace functions, but is there a way to do this with a dictionary in one shot? I've seen something like that in other languages: A one line command that can search text for all the keys in a dictionary and replace them with their values.
Is that possible in Python?
How about a dict comprehension:
filtered_dict = {k: v for k, v in d.iteritems() if filter_string in k}
One you see it, it should be self-explanatory, as it reads like English pretty well.
This syntax requires Python 2.7 or greater.
In Python 3, there is only dict.items(), not iteritems() so you would use:
filtered_dict = {k: v for k, v in d.items() if filter_string in k}
You can use the built-in filter function to filter dictionaries, lists, etc. based on specific conditions.
filtered_dict = dict(
filter(lambda item: filter_str in item[0], d.items())
)
The advantage is that you can use it for different data structures.