Iterating over list of dictionaries - python

I have a list -myList - where each element is a dictionary. I wish to iterate over this list but I am only interesting in one attribute - 'age' - in each dictionary each time. I am also interested in keeping count of the number of iterations.
I do:
for i, entry in enumerate(myList):
print i;
print entry['age'];
But was wondering is there something more pythonic. Any tips?

You could use a generator to only grab ages.
# Get a dictionary
myList = [{'age':x} for x in range(1,10)]
# Enumerate ages
for i, age in enumerate(d['age'] for d in myList):
print i,age
And, yeah, don't use semicolons.

Very simple way, list of dictionary iterate
>>> my_list
[{'age': 0, 'name': 'A'}, {'age': 1, 'name': 'B'}, {'age': 2, 'name': 'C'}, {'age': 3, 'name': 'D'}, {'age': 4, 'name': 'E'}, {'age': 5, 'name': 'F'}]
>>> ages = [li['age'] for li in my_list]
>>> ages
[0, 1, 2, 3, 4, 5]

For printing, probably what you're doing is just about right. But if you want to store the values, you could use a list comprehension:
>>> d_list = [dict((('age', x), ('foo', 1))) for x in range(10)]
>>> d_list
[{'age': 0, 'foo': 1}, {'age': 1, 'foo': 1}, {'age': 2, 'foo': 1}, {'age': 3, 'foo': 1}, {'age': 4, 'foo': 1}, {'age': 5, 'foo': 1}, {'age': 6, 'foo': 1}, {'age': 7, 'foo': 1}, {'age': 8, 'foo': 1}, {'age': 9, 'foo': 1}]
>>> ages = [d['age'] for d in d_list]
>>> ages
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> len(ages)
10

The semicolons at the end of lines aren't necessary in Python (though you can use them if you want to put multiple statements on the same line). So it would be more pythonic to omit them.
But the actual iteration strategy is easy to follow and pretty explicit about what you're doing. There are other ways to do it. But an explicit for-loop is perfectly pythonic.
(Niklas B.'s answer will not do precisely what you're doing: if you want to do something like that, the format string should be "{0}\n{1}".)

Related

Sort dictionary with attribute value

I have a list dictionary like this: {1: {'a': 5, 'score': 3}, 2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}} and want to sort it using its score attribute.
Intended output: {2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}, 1: {'a': 5, 'score': 3}}
I have trying to use the built-in function to sort the list but its not giving desired output
updatedList = sorted(b, key=lambda k: k['score'])
Any hints how I can get the desired output?
Your data structure is a nested dictionary, not a list.
To sort the dictionary, you can modify your key function to this:
>>> d = {1: {'a': 5, 'score': 3}, 2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}}
>>> dict(sorted(d.items(), key=lambda x: x[1]['score']))
{2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}, 1: {'a': 5, 'score': 3}}
Which converts the original dictionary to dict.items, then uses the score key from the dictionary in the (key, value) tuple. Then after sorting with sorted(), we can convert back to a dictionary with dict().
This works in Python 3.6+ since dictionaries are ordered. If you are using a lower python version, you can maintain dictionary insertion order with collections.OrderedDict instead.
For sorting a Nested Dictionary use the key argument for sorted(). It lets you specify a function that, given the actual item being sorted, returns a value that should be sorted by.
N_Dictionary = {1: {'a': 5, 'score': 3}, 2: {'a': 6, 'score': 1}, 3: {'a': 7, 'score': 2}}
s_values = sorted(N_Dictionary.items(), key = lambda x: x[1]["score"] )
s_values

Multiple similar values of a dictionary in an array changes when one of the values is modified

Let's say I'm performing some operation on an array as follows:
>>arr = np.array([1,2,34,567,433243,787,832])
>>h = np.where(arr < 100, {'hello' : 1}, {'hi' : 2 })
array([{'hello': 1}, {'hello': 1}, {'hello': 1}, {'hi': 2}, {'hi': 2},{'hi': 2}, {'hi': 2}], dtype=object)
When I try to add a key-value pair at some selective indices, It gets replicated across all the indices and gives me something like this:
>>h[0]['hola']=12
>>h[4]['heyy']=11
>>h
array([{'hello': 1, 'hola': 12}, {'hello': 1, 'hola': 12},{'hello': 1, 'hola': 12}, {'hi': 2, 'heyy': 11},{'hi': 2, 'heyy': 11}, {'hi': 2, 'heyy': 11},{'hi': 2, 'heyy': 11}], dtype=object)
While I expect the values to change only at those specific indices(0 & 4) and get something like this:
array([{'hello': 1, 'hola': 12}, {'hello': 1}, {'hello': 1}, {'hi': 2}, {'hi': 2, 'heyy': 11}, {'hi': 2,}, {'hi': 2}], dtype=object)
How do I obtain the desired output?.Thanks in advance
you are passing 3 args to np.where a condition an expression if its true and and expression if its false. These expressions are evaluated before being passed to the where method. Such that the dicts are created once for true and once for false then the same dict will be used whenever that Boolean value occurs in the expression.
Instaed you can just use a list comprehension to achieve what you want.
h = np.array([{'hello': 1} if i < 100 else {'hi': 2} for i in arr])

Combining multiple lists of dictionaries

I have several lists of dictionaries, where each dictionary contains a unique id value that is common among all lists. I'd like to combine them into a single list of dicts, where each dict is joined on that id value.
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
desired_output = [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
I tried doing something like the answer found at https://stackoverflow.com/a/42018660/7564393, but I'm getting very confused since I have more than 2 lists. Should I try using a defaultdict approach? More importantly, I am NOT always going to know the other values, only that the id value is present in all dicts.
You can use itertools.groupby():
from itertools import groupby
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
desired_output = []
for _, values in groupby(sorted([*list1, *list2, *list3], key=lambda x: x['id']), key=lambda x: x['id']):
temp = {}
for d in values:
temp.update(d)
desired_output.append(temp)
Result:
[{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
# combine all lists
d = {} # id -> dict
for l in [list1, list2, list3]:
for list_d in l:
if 'id' not in list_d: continue
id = list_d['id']
if id not in d:
d[id] = list_d
else:
d[id].update(list_d)
# dicts with same id are grouped together since id is used as key
res = [v for v in d.values()]
print(res)
You can first build a dict of dicts, then turn it into a list:
from itertools import chain
from collections import defaultdict
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
dict_out = defaultdict(dict)
for d in chain(list1, list2, list3):
dict_out[d['id']].update(d)
out = list(dict_out.values())
print(out)
# [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
itertools.chain allows you to iterate on all the dicts contained in the 3 lists. We build a dict dict_out having the id as key, and the corresponding dict being built as value. This way, we can easily update the already built part with the small dict of our current iteration.
Here, I have presented a functional approach without using itertools (which is excellent in rapid development work).
This solution will work for any number of lists as the function takes variable number of arguments and also let user to specify the type of return output (list/dict).
By default it returns list as you want that otherwise it returns dictionary in case if you pass as_list = False.
I preferred dictionary to solve this because its fast and search complexity is also less.
Just have a look at the below get_packed_list() function.
get_packed_list()
def get_packed_list(*dicts_lists, as_list=True):
output = {}
for dicts_list in dicts_lists:
for dictionary in dicts_list:
_id = dictionary.pop("id") # id() is in-built function so preferred _id
if _id not in output:
# Create new id
output[_id] = {"id": _id}
for key in dictionary:
output[_id][key] = dictionary[key]
dictionary["id"] = _id # push back the 'id' after work (call by reference mechanism)
if as_list:
return [output[key] for key in output]
return output # dictionary
Test
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
output = get_packed_list(list1, list2, list3)
print(output)
# [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
output = get_packed_list(list1, list2, list3, as_list=False)
print(output)
# {1: {'id': 1, 'value': 20, 'sum': 10, 'total': 30}, 2: {'id': 2, 'value': 21, 'sum': 11, 'total': 32}}
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
print(list1+list2+list3)
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
result = []
for i in range(0,len(list1)):
final_dict = dict(list(list1[i].items()) + list(list2[i].items()) + list(list3[i].items()))
result.append(final_dict)
print(result)
output : [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]

Ordering a Django queryset based on other list with ids and scores

I'm a bit mentally stuck at something, that seems really simple at first glance.
I'm grabbing a list of ids to be selected and scores to sort them based on.
My current solution is the following:
ids = [1, 2, 3, 4, 5]
items = Item.objects.filter(pk__in=ids)
Now I need to add a score based ordering somehow so I'll build the following list:
scores = [
{'id': 1, 'score': 15},
{'id': 2, 'score': 7},
{'id': 3, 'score': 17},
{'id': 4, 'score': 11},
{'id': 5, 'score': 9},
]
ids = [score['id'] for score in scores]
items = Item.objects.filter(pk__in=ids)
So far so good - but how do I actually add the scores as some sort of aggregate and sort the queryset based on them?
Sort the scores list, and fetch the queryset using in_bulk().
scores = [
{'id': 1, 'score': 15},
{'id': 2, 'score': 7},
{'id': 3, 'score': 17},
{'id': 4, 'score': 11},
{'id': 5, 'score': 9},
]
sorted_scores = sorted(scores) # use reverse=True for descending order
ids = [score['id'] for score in scores]
items = Item.objects.in_bulk(ids)
Then generate a list of the items in the order you want:
items_in_order = [items[x] for x in ids]

Selecting items in a dictionary using python

My goal is to first select the first 3 items in the dictionary below. I would also like to select items with values greater than 1.
dic=Counter({'school': 4, 'boy': 3, 'old': 3, 'the': 1})
My attempt:
1.>>> {x:x for x in dic if x[1]>1}
{'boy': 'boy', 'the': 'the', 'old': 'old', 'school': 'school'}
2.>>>dic[:3]
TypeError: unhashable type
Desired output: Counter({'school': 4, 'boy': 3, 'old': 3})
Thanks for your suggestions.
For items with count greater than one:
>>> [x for x in dic if dic[x] > 1]
['boy', 'school', 'old']
For the three most common items:
>>> [x for x, freq in dic.most_common(3)]
['school', 'boy', 'old']
To get dictionaries:
>>> {x: freq for x,freq in dic.items() if freq > 1}
{'boy': 3, 'school': 4, 'old': 3}
>>> {x: freq for x,freq in dic.most_common(3)}
{'boy': 3, 'school': 4, 'old': 3}
Note: Those are ordinary dictionaries. Use Counter(result) to turn them back into Counters. Alternatively to the dictionary comprehension you can also use the builtin dict function to turn a list of tuples into a dictionary, and then make a Counter from that.
>>> Counter(dict(dic.most_common(3)))
Counter({'school': 4, 'boy': 3, 'old': 3})

Categories