Python - Looping Over Specific Variables in a Dictionary - python

I'm trying to loop over everything in a dictionary [1:] but don't know how to do it and can't find the answer.
for value in self.legLocs.itervalues():
print x
And I'd think it would be something like
for value in self.legLocs.itervalues()[1:]:
print x
But that doesn't work. What's the correct way to do this?

Dictionaries don't have order, so you can't really loop over all of them except the first (as which element is the first isn't really defined). You can loop over the dict and exclude a specific key though:
def dict_keys_without(d,excludes_set):
return (k for k in d if k not in excludes_set)
which you can then use:
for key in dict_keys_without(d,{'foo','bar'}):
#do something with `k` or `d[k]`, etc.
And you could easily modify the above function to work with d.iteritems() or d.itervalues() or whatever criteria you want.
Of course, there's always the "Use a collections.OrderedDict" advice which is a dict subclass which does know it's order. If you're using an OrderedDict, then you could do something like:
values = iter(od.values())
_ = next(values,None) #scrap the first one
for value in values:
pass #Do something with the next values.

As #mgilson mentions, [1:] really has no meaning for a dict... If you're happy just ignoring some arbitrary entry, then you can use something like:
def skipone(d):
i = d()
next(i, None)
return i
d = {1:2, 3:4, 5:6}
for blah in skipone(d.iteritems): # or other function
pass
Alternatively:
from itertools import islice
def skip(obj, n=1):
i = obj() if callable(obj) else obj
return islice(i, n, None)

to "iterate" through a dictionary, do like this:
for key in aDict.keys():
if key != 'excluded': # You can check to see if it is the one you want to leave off
print(aDict[key])

if you want to iterate over all items:
for k,v in self.legLocs.items():
print "key",k
print "value",v
or like this:
for kv in self.legLocs.items():
k, v = kv
print "key",k
print "value",v
if you want to iterate only on keys:
for k in self.legLocs.keys():
print "key",k
if you want to iterate only on values:
for v in self.legLocs.values():
print "value",v

Related

filter items in a python dictionary where keys contain a specific string

I'm a C coder developing something in python. I know how to do the following in C (and hence in C-like logic applied to python), but I'm wondering what the 'Python' way of doing it is.
I have a dictionary d, and I'd like to operate on a subset of the items, only those whose key (string) contains a specific substring.
i.e. the C logic would be:
for key in d:
if filter_string in key:
# do something
else
# do nothing, continue
I'm imagining the python version would be something like
filtered_dict = crazy_python_syntax(d, substring)
for key,value in filtered_dict.iteritems():
# do something
I've found a lot of posts on here regarding filtering dictionaries, but couldn't find one which involved exactly this.
My dictionary is not nested and i'm using python 2.7
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}
Go for whatever is most readable and easily maintainable. Just because you can write it out in a single line doesn't mean that you should. Your existing solution is close to what I would use other than I would user iteritems to skip the value lookup, and I hate nested ifs if I can avoid them:
for key, val in d.iteritems():
if filter_string not in key:
continue
# do something
However if you realllly want something to let you iterate through a filtered dict then I would not do the two step process of building the filtered dict and then iterating through it, but instead use a generator, because what is more pythonic (and awesome) than a generator?
First we create our generator, and good design dictates that we make it abstract enough to be reusable:
# The implementation of my generator may look vaguely familiar, no?
def filter_dict(d, filter_string):
for key, val in d.iteritems():
if filter_string not in key:
continue
yield key, val
And then we can use the generator to solve your problem nice and cleanly with simple, understandable code:
for key, val in filter_dict(d, some_string):
# do something
In short: generators are awesome.
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.
input = {"A":"a", "B":"b", "C":"c"}
output = {k:v for (k,v) in input.items() if key_satifies_condition(k)}
Jonathon gave you an approach using dict comprehensions in his answer. Here is an approach that deals with your do something part.
If you want to do something with the values of the dictionary, you don't need a dictionary comprehension at all:
I'm using iteritems() since you tagged your question with python-2.7
results = map(some_function, [(k,v) for k,v in a_dict.iteritems() if 'foo' in k])
Now the result will be in a list with some_function applied to each key/value pair of the dictionary, that has foo in its key.
If you just want to deal with the values and ignore the keys, just change the list comprehension:
results = map(some_function, [v for k,v in a_dict.iteritems() if 'foo' in k])
some_function can be any callable, so a lambda would work as well:
results = map(lambda x: x*2, [v for k,v in a_dict.iteritems() if 'foo' in k])
The inner list is actually not required, as you can pass a generator expression to map as well:
>>> map(lambda a: a[0]*a[1], ((k,v) for k,v in {2:2, 3:2}.iteritems() if k == 2))
[4]
You can use the built-in function 'filter()':
data = {'aaa':12, 'bbb':23, 'ccc':8, 'ddd':34}
# filter by key
print(dict(filter(lambda e:e[0]=='bbb', data.items() ) ) )
# filter by value
print(dict(filter(lambda e:e[1]>18, data.items() ) ) )
OUTPUT:
{'bbb':23}
{'bbb':23, 'ddd':34}

Python Nested List Comprehension with If Else

I was trying to use a list comprehension to replace multiple possible string values in a list of values.
I have a list of column names which are taken from a cursor.description;
['UNIX_Time', 'col1_MCA', 'col2_MCA', 'col3_MCA', 'col1_MCB', 'col2_MCB', 'col3_MCB']
I then have header_replace;
{'MCB': 'SourceA', 'MCA': 'SourceB'}
I would like to replace the string values for header_replace.keys() found within the column names with the values.
I have had to use the following loop;
headers = []
for header in cursor.description:
replaced = False
for key in header_replace.keys():
if key in header[0]:
headers.append(str.replace(header[0], key, header_replace[key]))
replaced = True
break
if not replaced:
headers.append(header[0])
Which gives me the correct output;
['UNIX_Time', 'col1_SourceA', 'col2_SourceA', 'col3_SourceA', 'col1_SourceB', 'col2_SourceB', 'col3_SourceB']
I tried using this list comprehension;
[str.replace(i[0],k,header_replace[k]) if k in i[0] else i[0] for k in header_replace.keys() for i in cursor.description]
But it meant that items were duplicated for the unmatched keys and I would get;
['UNIX_Time', 'col1_MCA', 'col2_MCA', 'col3_MCA', 'col1_SourceA', 'col2_SourceA', 'col3_SourceA',
'UNIX_Time', 'col1_SourceB', 'col2_SourceB', 'col3_SourceB', 'col1_MCB', 'col2_MCB', 'col3_MCB']
But if instead I use;
[str.replace(i[0],k,header_replace[k]) for k in header_replace.keys() for i in cursor.description if k in i[0]]
#Bakuriu fixed syntax
I would get the correct replacement but then loose any items that didn't need to have an string replacement.
['col1_SourceA', 'col2_SourceA', 'col3_SourceA', 'col1_SourceB', 'col2_SourceB', 'col3_SourceB']
Is there a pythonesque way of doing this or am I over stretching list comprehensions? I certainly find them hard to read.
[str.replace(i[0],k,header_replace[k]) if k in i[0] for k in header_replace.keys() for i in cursor.description]
this is a SyntaxError, because if expressions must contain the else part. You probably meant:
[i[0].replace(k, header_replace[k]) for k in header_replace for i in cursor.description if k in i[0]]
With the if at the end. However I must say that list-comprehension with nested loops aren't usually the way to go.
I would use the expanded for loop. In fact I'd improve it removing the replaced flag:
headers = []
for header in cursor.description:
for key, repl in header_replace.items():
if key in header[0]:
headers.append(header[0].replace(key, repl))
break
else:
headers.append(header[0])
The else of the for loop is executed when no break is triggered during the iterations.
I don't understand why in your code you use str.replace(string, substring, replacement) instead of string.replace(substring, replacement). Strings have instance methods, so you them as such and not as if they were static methods of the class.
If your data is exactly as you described it, you don't need nested replacements and can boil it down to this line:
l = ['UNIX_Time', 'col1_MCA', 'col2_MCA', 'col3_MCA', 'col1_MCB', 'col2_MCB', 'col3_MCB']
[i.replace('_MC', '_Source') for i in l]
>>> ['UNIX_Time',
>>> 'col1_SourceA',
>>> 'col2_SourceA',
>>> 'col3_SourceA',
>>> 'col1_SourceB',
>>> 'col2_SourceB',
>>> 'col3_SourceB']
I guess a function will be more readable:
def repl(key):
for k, v in header_replace.items():
if k in key:
return key.replace(k, v)
return key
print map(repl, names)
Another (less readable) option:
import re
rx = '|'.join(header_replace)
print [re.sub(rx, lambda m: header_replace[m.group(0)], name) for name in names]

How to fetch the key/value pair of a dictionary only containing one item?

Let's say I have dict. I don't know the key/value inside. How do I get this key and the value without doing a for loop (there is only one item in the dict).
You might wonder why I am using a dictionary in that case. I have dictionaries all over my API and I don't want the user to be lost. It's only a matter of consistency. Otherwise, I would have used a list and indexes.
Use the proper data type for the job. Your goal should be to have workable code, not that you use the same data type all over the place.
If your dictionary only contains one key and one value, you can get either with indexing:
key = list(d)[0]
value = list(d.values())[0]
or to get both:
key, value = list(d.items())[0]
The list calls are needed because in Python 3, .keys(), .values() and .items() return dict views, not lists.
Another option is to use sequence unpacking:
key, = d
value, = d.values()
or for both at the same time:
(key, value), = d.items()
Just get the first item in the dictionary using an iterator
>>> d = {"foo":"bar"}
>>> k, v = next(iter(d.items()))
>>> k
'foo'
>>> v
'bar'
You can do this:
>>> d={1:'one'}
>>> k=list(d)[0]
>>> v=d[k]
Works in Python 2 or 3
d.popitem() will give you a key,value tuple.

Searching key/values with defaultdict

I'm familiar with the use of the iteritems() and items() use with the standard dictionary which can be coupled with a for loop to scan over keys and values. However how can I best do this with the default dict. For example, I'd like to check that a given value does not show up in either the key or any of the values associated with any key. I'm currently trying the following:
for key, val in dic.iteritems():
print key, val
however I get the following:
1 deque([2, 2])
and I have the following declarations for the variables/dictionary
from collections import defaultdict, deque
clusterdict = defaultdict(deque)
So how do I best get at key values? Thanks!
In general, for a defaultdict dd, to check whether a value x is used as a key do this:
x in dd
To check whether x is used as a value do this:
x in dd.itervalues()
In your case (a defaultdict with deques as values), you may want to see whether x is in any of the deques:
any(x in deq for deq in dd.itervalues())
Remember, defaultdicts behave like regular dictionaries except that they create new entries automatically when doing d[k] lookups on missing keys; otherwise, they behave no differently than regular dicts.
If I understood your question:
for key, val in dic.iteritems():
if key!=given_value and not given_value in val:
print "it's not there!"
Unless you meant something else...
I made this for Python 3:
from collections import defaultdict
count_data = defaultdict(int)
count_data[1] = 10
query = 2
if query in count_data.values():
print('yes')
Edit
You can use Counter dictionary too:
from collections import Counter
count_data = Counter()
count_data[1] = 10
query = 2
if query in count_data.values():
print('yes')
stuff = 'value to check'
if not any((suff in key or stuff in value) for key, value in dic.iteritems()):
# do something if stuff not in any key or value
http://docs.python.org/library/collections.html#collections.defaultdict
So you can use iteritems

Efficient way to either create a list, or append to it if one already exists?

I'm going through a whole bunch of tuples with a many-to-many correlation, and I want to make a dictionary where each b of (a,b) has a list of all the a's that correspond to a b. It seems awkward to test for a list at key b in the dictionary, then look for an a, then append a if it's not already there, every single time through the tuple digesting loop; but I haven't found a better way yet. Does one exist? Is there some other way to do this that's a lot prettier?
See the docs for the setdefault() method:
setdefault(key[, default])
If key is
in the dictionary, return its value.
If not, insert key with a value of
default and return default. default
defaults to None.
You can use this as a single call that will get b if it exists, or set b to an empty list if it doesn't already exist - and either way, return b:
>>> key = 'b'
>>> val = 'a'
>>> print d
{}
>>> d.setdefault(key, []).append(val)
>>> print d
{'b': ['a']}
>>> d.setdefault(key, []).append('zee')
>>> print d
{'b': ['a', 'zee']}
Combine this with a simple "not in" check and you've done what you're after in three lines:
>>> b = d.setdefault('b', [])
>>> if val not in b:
... b.append(val)
...
>>> print d
{'b': ['a', 'zee', 'c']}
Assuming you're not really tied to lists, defaultdict and set are quite handy.
import collections
d = collections.defaultdict(set)
for a, b in mappings:
d[b].add(a)
If you really want lists instead of sets, you could follow this with a
for k, v in d.iteritems():
d[k] = list(v)
And if you really want a dict instead of a defaultdict, you can say
d = dict(d)
I don't really see any reason you'd want to, though.
Use collections.defaultdict
your_dict = defaultdict(list)
for (a,b) in your_list:
your_dict[b].append(a)
you can sort your tuples O(n log n) then create your dictionary O(n)
or simplier O(n) but could impose heavy load on memory in case of many tuples:
your_dict = {}
for (a,b) in your_list:
if b in your_dict:
your_dict[b].append(a)
else:
your_dict[b]=[a]
Hmm it's pretty much the same as you've described. What's awkward about that?
You could also consider using an sql database to do the dirty work.
Instead of using an if, AFAIK it is more pythonic to use a try block instead.
your_list=[('a',1),('a',3),('b',1),('f',1),('a',2),('z',1)]
your_dict={}
for (a,b) in your_list:
try:
your_dict[b].append(a)
except KeyError:
your_dict[b]=[a]
print your_dict
I am not sure how you will get out of the key test, but once they key/value pair has been initialized it is easy :)
d = {}
if 'b' not in d:
d['b'] = set()
d['b'].add('a')
The set will ensure that only 1 of 'a' is in the collection. You need to do the initial 'b' check though to make sure the key/value exist.
Dict get method?
It returns the value of my_dict[some_key] if some_key is in the dictionary, and if not - returns some default value ([] in the example below):
my_dict[some_key] = my_dict.get(some_key, []).append(something_else)
There's another way that's rather efficient (though maybe not as efficient as sets) and simple. It's similar in practice to defaultdict but does not require an additional import.
Granted that you have a dict with empty (None) keys, it means you also create the dict keys somewhere. You can do so with the dict.fromkeys method, and this method also allows for setting a default value to all keys.
keylist = ['key1', 'key2']
result = dict.fromkeys(keylist, [])
where result will be:
{'key1': [], 'key2': []}
Then you can do your loop and use result['key1'].append(..) directly

Categories

Resources