Iterate through series of dictionaries - python

I am trying to define a series of dictionaries and then iterate through them below. I've tried putting the dictionary names into a list to iterate over, but that then throws up an error that a string does not have .keys() method. I'm presuming that is because Python thinks the values in the list are just strings and not meant to represent the dictionaries above.
I'm not sure how else I could code this though. The code is here:
prem_year_map = {
2011: 2935,
2012: 3389,
2013: 3853,
2014: 4311,
}
year_tournament_map = {
2013: 8273,
2012: 6978,
2011: 5861,
2010: 4940,
}
tournament_list = [prem_year_map, year_tournament_map]
for x in tournament_list:
years = sorted(tournament_list.keys())
print years
Can anyone suggest an alternative method?
Thanks

I'm presuming that is because Python thinks the values in the list are just strings and not meant to represent the dictionaries above.
This is not right. A list in Python can contain any type of reference.
You simply need to use the object.keys() instead of tournament_list.keys() (the latter you are asking for keys of the list, which do not exist - the dictionaries have the keys)
for x in tournament_list:
years = sorted(x.keys())
print years
As pointed out by #JonClements you can also used sorted(x) which returns a list (and is a bit more efficient in Python 2.x). Note that it can't return a dictionary since the standard dictionary cannot preserve an order.

To iterate dictionary key and value you need use different iterator.
for key, value in {}.iteritems():
print key, value
The best choice is standard itertools.
for key, value in itertools.chain(dict1.iteritems(), dict2.iteritems())
print key, value
You can also do list of iterators and iterate them.
iterators = []
iterators.append(oneDict.iteritems())
for iterator in iterators:
for item in iterator:
yield item # (key, value)
Choose what is the simplest.

It should be:
for x in tournament_list:
years = sorted(x.keys())
print years
Otherwise you are trying to get the keys from the list of dictionaries (which of course make no sense).

Related

In Python 3.X, how do you program a print to only occur if the input.split() contains none of the items being checked in a for loop? [duplicate]

Given the following code
all_options = { "1": "/test/1", "2": "/test/2", "3": "/test/3" }
selected_options = [ "1", "3" ]
How do I get the entries from all_options where the key matches an entry in selected_options?
I started down the path of using a List Comprehension, but I'm stuck on the last clause:
final = ()
[ final.append(option) for option in all_options if ... ]
Thank you
Just like this?
>>> dict((option, all_options[option]) for option in selected_options if option in all_options)
{'1': '/test/1', '3': '/test/3'}
From Python 2.7 and 3 onwards, you can use the dict comprehension syntax:
{option : all_options[option] for option in selected_options if option in all_options}
Or if you just want the values:
>>> [all_options[option] for option in selected_options if option in all_options]
['/test/1', '/test/3']
[option for option in all_options if option in selected_options]
You may want to make a set of selected_options and use that instead if there are many.
How do I get the entries from all_options where the key matches an entry in selected_options?
With a comprehension. We have two kinds: list comprehensions and generator comprehensions.
Note that this depends on what you mean by "entries". If you want a dict with the key/value pairs that match, then you'll need a comprehension that creates the key/value pairs, and then use that to create a dict by feeding it to the dict constructor.
There is a special syntax rule that says that if we call something callable (like, say, a class constructor) with just one argument, and that argument is a generator comprehension, then we only need one pair of parentheses (instead of two: one to call the function and another to mark the comprehension as a comprehension). This lets us write very natural-looking things.
On the other hand, if you just want a list of keys, then you can just use a list comprehension. (You could pass a generator comprehension to the list constructor, too.)
I started down the path of using a List Comprehension...
You have the wrong idea, fundamentally, about how they work. You don't use them to perform an action repeatedly; you use them to calculate a result repeatedly. You wouldn't make an append call in the first part of the statement because (a) the comprehension is already building the sequence for you, so there's no reason to create another empty sequence to append to; (b) the append call returns None after doing the appending, so you end up with a list of None values that you subsequently throw away.
A list comprehension creates a value. A generator comprehension also creates a value, but it's a generator (so you have to extract its values to use them).
So, how do we write the code?
A list of keys looks like this: for each key in the dict (iterating over a dict iterates over its keys), we want that key (with no modification), only if the key is in our other list. That is, we want [key for key in all_options if key in selected_options]. And that's exactly how you write it in Python. A language could hardly read any more naturally while still being unambiguous.
A dict of key-value pairs looks like this: for each key-value pair in the key-value pairs of the dict, we want that pair, only if the key is in our other list. We want to make a dict using those key-value pairs, so we wrap the comprehension in the dict constructor. To get key-value pairs from a dict, we iterate over its .items(). So, we want a dict constructed from a key and value, for each key and value in the items of the original dict, where the key is in the other list. And again, that's exactly what we write: dict((key, value) for (key, value) in all_options if key in selected_options).
In more recent versions of Python, we can also use a "dict comprehension", which is basically syntactic sugar so that we can write something that looks more like the list comprehension.
Use set() instead, and take advantage of the intersection operation:
>>> final = set(all_options.keys()) & set(selected_options)
>>> print(final)
{'1', '3'}
The above only returns the keys, but NullUserException notes that the question may want the value as well, using a dict comprehention:
>>> {x: all_options[x] for x in set(all_options.keys()) & set(selected_options)}
{'1': '/test/1', '3': '/test/3'}
For completeness, here's just the value:
>>> [all_options[x] for x in set(all_options.keys()) & set(select_options)]
['/test/1', '/test/3']
The below is wrong. Using set() iterates over both lists, instead of just one.
Using sets is better assuming the options become large. The conditional list comprehensions check every item in one of the containers, but a set intersection takes advantage of Python's excellent hashing. Even the list comprehension here only looks up the desired keys in all_options.
I'm not sure which exact contents you're trying to return, so I'm giving a couple of choices:
if your trying to return: ['1', '3']
[option for option in all_options if option in selected_options]
OR
if you're trying to return: ['/test/1', '/test/3']
[all_options[option] for option in all_options if option in selected_options]

dict_key and dict_value to list performances [duplicate]

This question already has answers here:
Accessing dict_keys element by index in Python3
(7 answers)
Closed 2 years ago.
I have this sentence:
def Ciudad(prob):
numero = random.random()
ciudad = prob.keys()[0]
for i in prob.keys():
if(numero > prob[i]):
if(prob[i] > prob[ciudad]):
ciudad = i
else:
if(prob[i] > prob[ciudad]):
ciudad = i
return ciudad
But when I call it this error pops:
TypeError: 'dict_keys' object does not support indexing
is it a version problem? I'm using Python 3.3.2
dict.keys() is a dictionary view. Just use list() directly on the dictionary instead if you need a list of keys, item 0 will be the first key in the (arbitrary) dictionary order:
list(prob)[0]
or better still just use:
next(iter(dict))
Either method works in both Python 2 and 3 and the next() option is certainly more efficient for Python 2 than using dict.keys(). Note however that dictionaries have no set order and you will not know what key will be listed first.
It looks as if you are trying to find the maximum key instead, use max() with dict.get:
def Ciudad(prob):
return max(prob, key=prob.get)
The function result is certainly going to be the same for any given prob dictionary, as your code doesn't differ in codepaths between the random number comparison branches of the if statement.
In Python 3.x, dict.keys() does not return a list, it returns an iterable (specifically, a dictionary view). It is worth noting that dict itself is also an iterable of the keys.
If you want to obtain the first key, use next(iter(dict)) instead. (Note that before Python 3.6 dictionaries were unordered, so the 'first' element was an arbitrary one. Since 3.6 it will be based on insertion order. If you need that behaviour in older versions or with cross-version compatibility, you can use collections.OrderedDict).
This works quite simply: we take the iterable from the dictionary view with iter(), then use next() to advance it by one and get the first key.
If you need to iterate over the keys—then there is definitely no need to construct a list:
for key in dict:
...
These are all advantageous when compared to using list() as it means a list isn't constructed - making it faster and more memory efficient (hence why the default behaviour of keys() was changed in 3.x). Even in Python 2.x you would be better off doing next(iter(dict.iterkeys()).
Note all these things apply to dict.values() and dict.items() as well.
I've had success turning the iterables taken from a dictionary into a list.
So, for dic.keys(), dic.values(), and dic.items(), in Python3.6, you can:
dic = {'a':3, 'b':2, 'c':3}
print(dic)
dictkeys = dic.keys() # or values/items
print(dictkeys)
keylist = []
keylist.extend(iter(dictkeys)) # my big revelation
print('keylist', keylist)

Join dictionary item, keys [duplicate]

This question already has answers here:
Iterating over dictionaries using 'for' loops
(15 answers)
Closed 8 years ago.
Please see below code snippet for join method (used Python 2.7.2):
iDict={'1_key':'abcd','2_key':'ABCD','3_key':'bcde','4_key':'BCDE'}
'--'.join(iDict)
Result shown as
'2_key--1_key--4_key--3_key'
Please comment why only keys are joined? Also the sequence is not in order.
Note - below are the individual methods.
'--'.join(iDict.values()) ==> 'ABCD--abcd--BCDE--bcde' ==> the sequence is not in order
'--'.join(iDict.keys()) ==> '2_key--1_key--4_key--3_key' ==> the sequence is not in orde
If you see the docs, you learn that iterating over dict returns keys.
You need to iterate over dict.items(), that it over tuples (key, value):
'--'.join(iDict.items())
If you need to have key AND value joined in one string, you need to explicitly tell Python how to do this:
'--'.join('{} : {}'.format(key, value) for key, value in iDict.items())
Python dictionaries are unordered (or rather, their order is arbitrary), and when you iterate on them, only the keys are returned:
>>> d = {'0':0, '1':1, '2':2, '3':3, '4':4}
>>> print(d)
{'4': 4, '1': 1, '0': 0, '3': 3, '2': 2}
If you need both keys and values, use iDict.items().
If you need ordering, use collections.OrderedDict.
Iteration over a dictionary only ever yields keys:
>>> list(iDict)
['2_key', '1_key', '4_key', '3_key']
See the dict() documentation:
iter(d)
Return an iterator over the keys of the dictionary. This is a shortcut for iterkeys().
Both list() and str.join() will call iter() on their arguments to iterate over the elements.
Dictionaries are unordered containers; their order stems from the underlying data structure and depends on the insertion and deletion history of the keys.
This is documented under dict.items():
CPython implementation detail: Keys and values are listed in an arbitrary order which is non-random, varies across Python implementations, and depends on the dictionary’s history of insertions and deletions.
Also see Why is the order in dictionaries and sets arbitrary?

how to write a conditional list comprehension, with "extend" functionality [duplicate]

This question already has answers here:
How do I make a flat list out of a list of lists?
(34 answers)
Closed 9 years ago.
I want to write a nice one line list comprehension with "extend functionality", that also includes a conditional. here is what I have that works
nouns = []
[nouns.extend(value)/ for key, value in pos_dictionary.iteritems()
if key.startswith('NN') ]
ideally I write something nice like
nouns = [nouns.extend(value) for key, value in pos_dictionary.iteritems()
if key.startswith('NN') ]
Which doesn't work because I haven't defined the list yet. The former isn't super horrible, essentially using the comprehension as functional List.iter statement. While I am new to python, this still doesn't seem like the correct style. If this is the proper style, I would appreciate some verification.
I am encountering this sceneario because I am looking to aggregate all the different types of Nouns Tags from the POS tagger (using NLTK) into a single list.
Edit: I agree it is nearly a duplicate, i didn't think if this as flattening a list, but now that it has been introduced as a possibility i can accept it. The one variant is that my example did include a conditional in the comprehension. Also I was inquiring as to the preferred idiomatic syntax, which while possibly open ended is a nice bit for a newbie to python.
Not everything is done best with a single list comprehension. While you could do
nouns = [x for key, value in pos_dictionary.iteritems() if key.startswith('NN') for x in value]
I really think that
nouns = []
for key, value in pos_dictionary.iteritems():
if key.startswith('NN'):
nouns += value
is far more redable.
You can use itertools.chain.from_iterable() to stitch together a sequence of lists:
from itertools import chain
nouns = list(chain.from_iterable(value
for key, value in pos_dictionary.iteritems()
if key.startswith('NN')))
If you essentially want to run multiple list comprehensions that all contribute to the same final list, you can just create your separate list comprehensions like normal, and simple concat the lists then.
For example:
nouns1 = [value for key, value in pos_dictionary.iteritems() if key.startswith('NN')]
nouns2 = [value for somethingElse]
nouns3 = [value for andOneMore]
nouns = nouns1 + nouns2 + nouns3
sum([value for key, value in pos_dictionary.iteritems() if key.startswith('NN') ],[])
although its slower ...

append multiple values for one key in a dictionary [duplicate]

This question already has answers here:
list to dictionary conversion with multiple values per key?
(7 answers)
Closed 4 years ago.
I am new to python and I have a list of years and values for each year. What I want to do is check if the year already exists in a dictionary and if it does, append the value to that list of values for the specific key.
So for instance, I have a list of years and have one value for each year:
2010
2
2009
4
1989
8
2009
7
What I want to do is populate a dictionary with the years as keys and those single digit numbers as values. However, if I have 2009 listed twice, I want to append that second value to my list of values in that dictionary, so I want:
2010: 2
2009: 4, 7
1989: 8
Right now I have the following:
d = dict()
years = []
(get 2 column list of years and values)
for line in list:
year = line[0]
value = line[1]
for line in list:
if year in d.keys():
d[value].append(value)
else:
d[value] = value
d[year] = year
If I can rephrase your question, what you want is a dictionary with the years as keys and an array for each year containing a list of values associated with that year, right? Here's how I'd do it:
years_dict = dict()
for line in list:
if line[0] in years_dict:
# append the new number to the existing array at this slot
years_dict[line[0]].append(line[1])
else:
# create a new array in this slot
years_dict[line[0]] = [line[1]]
What you should end up with in years_dict is a dictionary that looks like the following:
{
"2010": [2],
"2009": [4,7],
"1989": [8]
}
In general, it's poor programming practice to create "parallel arrays", where items are implicitly associated with each other by having the same index rather than being proper children of a container that encompasses them both.
You would be best off using collections.defaultdict (added in Python 2.5). This allows you to specify the default object type of a missing key (such as a list).
So instead of creating a key if it doesn't exist first and then appending to the value of the key, you cut out the middle-man and just directly append to non-existing keys to get the desired result.
A quick example using your data:
>>> from collections import defaultdict
>>> data = [(2010, 2), (2009, 4), (1989, 8), (2009, 7)]
>>> d = defaultdict(list)
>>> d
defaultdict(<type 'list'>, {})
>>> for year, month in data:
... d[year].append(month)
...
>>> d
defaultdict(<type 'list'>, {2009: [4, 7], 2010: [2], 1989: [8]})
This way you don't have to worry about whether you've seen a digit associated with a year or not. You just append and forget, knowing that a missing key will always be a list. If a key already exists, then it will just be appended to.
You can use setdefault.
for line in list:
d.setdefault(year, []).append(value)
This works because setdefault returns the list as well as setting it on the dictionary, and because a list is mutable, appending to the version returned by setdefault is the same as appending it to the version inside the dictionary itself. If that makes any sense.
d = {}
# import list of year,value pairs
for year,value in mylist:
try:
d[year].append(value)
except KeyError:
d[year] = [value]
The Python way - it is easier to receive forgiveness than ask permission!
Here is an alternative way of doing this using the not in operator:
# define an empty dict
years_dict = dict()
for line in list:
# here define what key is, for example,
key = line[0]
# check if key is already present in dict
if key not in years_dict:
years_dict[key] = []
# append some value
years_dict[key].append(some.value)
It's easier if you get these values into a list of tuples. To do this, you can use list slicing and the zip function.
data_in = [2010,2,2009,4,1989,8,2009,7]
data_pairs = zip(data_in[::2],data_in[1::2])
Zip takes an arbitrary number of lists, in this case the even and odd entries of data_in, and puts them together into a tuple.
Now we can use the setdefault method.
data_dict = {}
for x in data_pairs:
data_dict.setdefault(x[0],[]).append(x[1])
setdefault takes a key and a default value, and returns either associated value, or if there is no current value, the default value. In this case, we will either get an empty or populated list, which we then append the current value to.
If you want a (almost) one-liner:
from collections import deque
d = {}
deque((d.setdefault(year, []).append(value) for year, value in source_of_data), maxlen=0)
Using dict.setdefault, you can encapsulate the idea of "check if the key already exists and make a new list if not" into a single call. This allows you to write a generator expression which is consumed by deque as efficiently as possible since the queue length is set to zero. The deque will be discarded immediately and the result will be in d.
This is something I just did for fun. I don't recommend using it. There is a time and a place to consume arbitrary iterables through a deque, and this is definitely not it.

Categories

Resources