Nested If Statement not Evaluating as expected - python

I have two lists that I am trying to compare :
a = [{'name': 'ORANGES_060222', 'bushels': 5}, {'name': 'BANANAS_062620', 'bushels': 3}]
b = ['oranges', 'bananas', 'apples']
I just want to see if any element of a's name value can be matched to b and if so append the bushel value to an empty list. Like so:
f = []
a = [{'name': 'ORANGES_060222', 'bushels': 5}, {'name': 'BANANAS_062620', 'bushels': 3}]
b = ['oranges', 'bananas', 'apples']
for item in a:
if item['name'].lower() in b:
f.append(item['bushels'])
print(f)
f is returning [], the problem seems to be in the if statement. Not sure but seems like I might be attempting the wrong operation there?

item['name'].lower() in b won't work as you intend because the strings don't match exactly. For instance 'ORANGES_060222' isn't the same as 'orange' (even with lower).
Instead you can remove all non alphabet characters using isalpha
item_name = ''.join([c for c in item['name'].lower() if c.isalpha()])
if item_name in b:
...

You are probably looking for something like this -
f = []
a = [{'name': 'ORANGES_060222', 'bushels': 5}, {'name': 'BANANAS_062620', 'bushels': 3}]
b = ['oranges', 'bananas', 'apples']
for item in a:
for b_items in b:
if b_items in item['name'].lower():
f.append(item['bushels'])
print(f)
Output :
[5, 3]
What this does is checks if any of b exists in a. In your code, you were doing item['name'].lower() which returns ORANGES_060222 which doesn't exists in b. What you probably wanted to check if orange part from a[0] existed in b.
You can also do it as -
f = []
a = [{'name': 'ORANGES_060222', 'bushels': 5}, {'name': 'BANANAS_062620', 'bushels': 3}]
b = ['oranges', 'bananas', 'apples']
for item in a:
if item['name'].lower().split('_')[0] in b:
f.append(item['bushels'])
print(f)
Output :
[5, 3]
This method can be used if every element in a occurs in the format - NAME_NUMBER. So, item['name'].lower().split('_')[0] will only return the name part ( oranges in the first case ) and then you can check if it exists in b to get the desired results.
Hope this helps !

You should do the reverse:
f = []
a = [{'name': 'ORANGES_060222', 'bushels': 5}, {'name': 'BANANAS_062620', 'bushels': 3}]
b = ['oranges', 'bananas', 'apples']
for item in a:
for x in b:
if b in item['name'].lower():
f.append(item['bushels'])
break
print(f)

You can simply use this nested list comprehension:
f = [item['bushels'] for item in a for d in b if d in item['name'].lower()]

Related

how to add/merge values together in a python dictionary

I have two list
alist = [1,2,5,3,7,3,21,7,2]
blist = [mary, tom, ken, mary, tom, peter, joseph, mary, ken]
in the end I would like to have a python dictionary:
{"mary": 11, "tom": 9, "ken": 7, "peter": 7, "joseph":21}
adding all their marks together according to their names.
I tried something like this:
for (marks, name) in zip(alist,blist):
dict[name] += marks
I have this solution:
d = dict()
for (marks, name) in zip(alist,blist):
if name in d:
d[name] += marks
else:
d[name] = marks
Maybe something more efficient could be written but I think this works.
You can use collections.Counter, it is probably the most efficient way of doing this.
from collections import Counter
c = Counter()
for mark, name in zip(alist, blist):
c[name] += mark
print(c)
Output:
Counter({'joseph': 21, 'mary': 11, 'tom': 9, 'ken': 7, 'peter': 3})
Counter works just like a dictionary, but extends it with some additional methods like:
print(c.most_common(3))
Output:
[('joseph', 21), ('mary', 11), ('tom', 9)]
zip(*iterables)
Make an iterator that aggregates elements from each of the iterables.
https://docs.python.org/3.3/library/functions.html#zip
from collections import defaultdict
alist = [1,2,5,3,7,3,21,7,2]
blist = ['mary', 'tom', 'ken', 'mary', 'tom', 'peter', 'joseph', 'mary', 'ken']
data_dict = defaultdict(int)
for i, count in zip(blist, alist):
data_dict[i] += count
You can use this solution alternatively
alist = [1,2,5,3,7,3,21,7,2]
blist = ['mary', 'tom', 'ken', 'mary', 'tom', 'peter', 'joseph', 'mary', 'ken']
my_dict = {}
for key, value in zip(blist, alist):
my_dict[key] = my_dict.get(key, 0) + value
dict(zip(alist, blist))
This may help taken from this article https://www.geeksforgeeks.org/python-convert-two-lists-into-a-dictionary/amp/

Find the index from values in a list inside a dictionary

Does any one knows how to get the index of the values from dictionary 2 on dictionary 1.. like this:
Dictionary_1= {A: [Tom, Jane, Joe]; B: [Joana, Clare, Tom]; C: [Clare, Jane, Joe]}
Dictionary_2 = {A: Tom; B: Clare; C: Jane}
RESULT = {A: 1; B: 2; C: 2}
EDIT:
Sorry guys.. first of all I got confused and forgot that I needed it starting with "0" instead of "1".
I was having a problem, but it was because my list inside of dictionary 1 was in unicode format instead of list.
Also.. in the example I used here, I noticed later that the keys existed in both dictionaries, but in the code Im writting it wasnt the same thing. I didnt post the original here because it was bigger, so I tried to resume the most I could. Sorry for that too.
So I got it working with this code:
RESULT = {}
for x, y in Dictionary_1.items():
for a, b in Dictionary_2 .items():
if x == a:
z = Dictionary_1[x]
r = eval(z)
if '{0}'.format(b) in r:
RESULT [a] = r.index('{0}'.format(b))
I know that its looks messy but im still learning.
I really appreciate your help guys!
You can try using dict comprehension.
dict1={'A':['Tom','Jane','Joe'],'B':['Joana','Clare','Tom'],'C':['Clare','Jane','Joe']}
dict2={'A':'Tom','B':'Clare','C':'Jane'}
result={k:dict1[k].index(v)+1 for k,v in dict2.values()}
# {'A': 1, 'B': 2, 'C': 2}
#Or
# {k:dict1.get(k).index(v)+1 for k,v in dict2.items()}
Assuming you want 0-based indices, you can use list.index() with a dict comprehension:
d1 = {'A': ['Tom', 'Jane', 'Joe'], 'B': ['Joana', 'Clare', 'Tom'], 'C': ['Clare', 'Jane', 'Joe']}
d2 = {'A': 'Tom', 'B': 'Clare', 'C': 'Jane'}
result = {k: d1[k].index(v) for k, v in d2.items()}
print(result)
# {'A': 0, 'B': 1, 'C': 1}
If you want to have indices starting at 1, then you can do d1[k].index(v) + 1.
An easy to understand solution for you
d1 = {'A': ['Tom', 'Jane', 'Joe'], 'B': ['Joana', 'Clare', 'Tom'], 'C': ['Clare', 'Jane', 'Joe']}
d2 = {'A': 'Tom', 'B': 'Clare', 'C': 'Jane'}
output = {}
for k,v in d2.items():
output[k] = d1[k].index(v)+1
print(output)
This is certainly not the best approach but this is what I did quickly:
dict1 = {0: ['Tom', 'Jane', 'Joe'], 1: ['Joana', 'Clare', 'Tom'], 2: ['Clare', 'Jane', 'Joe']}
dict2 ={0: 'Tom', 1: 'Clare', 2: 'Jane'}
result = {}
val_list = list(dict1.values())
for i in range(0,len(dict1)):
result.update({i : val_list[i].index(dict2[i])})
print(result)

One-liner for updating a value in a list of dictionaries - Python

I have a list of dictionaries like so:
l = [{"integer":"1"},{"integer":"2"},{"integer":"3"},{"integer":"4"}]
I would like to do something similar to the following so that each of the numbers which are the value pair for the "integer" key are returned as integers:
l = [{"integer":"1"},{"integer":"2"},{"integer":"3"},{"integer":"4"}]
r = map(lambda x: x["integer"]=int(x["integer"]), l)
print r
#[{"integer":1},{"integer":2},{"integer":3},{"integer":4}]
But this causes an error:
SyntaxError: lambda cannot contain assignment
Does anyone know of a clean way to do this in python? Preferably a oneliner using map or something similar?
Use a list comprehension comprehension
You will iterate through the dictionaries in the list and have them returned as x, then insert a new dictionary with your desired key and the integer value of the return within a new list
r = [{'integer': int(x['integer'])} for x in l]
You should just use a loop:
l = [{"integer":"1"},{"integer":"2"},{"integer":"3"},{"integer":"4"}]
for d in l:
d["integer"] = int(d["integer"])
print(l)
#[{'integer': 1}, {'integer': 2}, {'integer': 3}, {'integer': 4}]
However, here is a one-liner that should work for you:
l = [{"integer":"1"},{"integer":"2"},{"integer":"3"},{"integer":"4"}]
[d.update({"integer": int(d["integer"])}) for d in l]
print(l)
#[{'integer': 1}, {'integer': 2}, {'integer': 3}, {'integer': 4}]
Be aware that dict.update() returns None, so if you assigned the output of the list comprehension to a variable it would be a list containing all Nones.
print([d.update({"integer": int(d["integer"])}) for d in l])
#[None, None, None, None]
The following works in one line:
r = [{'integer':int(x['integer'])} for x in l]
print(r)
# [{'integer': 1}, {'integer': 2}, {'integer': 3}, {'integer': 4}]
This utilizes a dict comprehension inside a list comprehension.
[i.update({w:int(k)}) for i in l for w,k in i.items()]
it the second loop is only looping over one key set, so take the two loops with gram of salt :)
Awesome solution by one of my friends in a chat:
>>> listOfDict = [{1:1338}, {1:1338}, {1:1338}]
>>> y = 1337
>>> value = 1
>>> map(lambda x: x.update({value: y}), listOfDict)
[None, None, None]
>>> listOfDict
[{1: 1337}, {1: 1337}, {1: 1337}]
You can try the following
l = [{"integer":"1"},{"integer":"2"},{"integer":"3"},{"integer":"4"}]
a = [dict(d, **{'abcd':5}) for d in l]
print(a)
[{'integer': '1', 'abcd': 4}, {'integer': '2', 'abcd': 4}, {'integer': '3', 'abcd': 4}, {'integer': '4', 'abcd': 4}]

Python - merge two list of dictionaries adding values of repeated keys

So I have two list of dictionaries which look like the following:
A = [{'id':'xyz', 'count': 3},{'id':'zzz', 'count': 1}]
B = [{'id':'xyz', 'count': 4}]
I want the final output to be like:
C = [{'id':'xyz', 'count': 7},{'id':'zzz', 'count': 1}]
So in case that if the value of the first key is the same in both lists, we add up the values for the second key. Any idea how I might achieve this? So far I have tried:
for elem in A:
if elem['id'] in B.elementsKey['id']:
# TO DO
I am stock where I am trying to update the value for the other element accordingly.
NOTE: Each id is unique.
Thanks
from collections import Counter
C_counts = Counter()
for l in (A, B):
C_counts.update({x['id']: x['count'] for x in l})
C = [{'id':k, 'count':c} for (k, c) in C_counts.items()]
If you really don't want to import collections.Counter you can do:
_C = {}
for l in A, B:
for d in l:
_C[d['id']] = d['count'] + _C.get(d['id'], 0)
C = [{'id':k, 'count':c} for (k, c) in _C.items()]
Here's one way to do it using itertools.groupby:
from itertools import groupby
from operator import itemgetter
f = itemgetter('id')
lst = [{'id': k, 'count': sum(d['count'] for d in g)}
for k, g in groupby(sorted(A+B, key=f), f)]
print(lst)
# [{'id': 'xyz', 'count': 7}, {'id': 'zzz', 'count': 1}]

python appending a dictonary to list is changing all the list elements [duplicate]

This question already has an answer here:
Python The appended element in the list changes as its original variable changes
(1 answer)
Closed 8 years ago.
I want list d = [{'name': 'Ada Lovelace'},{'name': 'Alan Turing'}].
But the dictionary mutates
>>> a = ['Ada Lovelace','Alan Turing']
>>> c = dict()
>>> d = []
>>> for i in a:
... print c
... print d
... c['name'] = i
... d.append(c)
... print c
... print d
...
{}
[]
{'name': 'Ada Lovelace'}
[{'name': 'Ada Lovelace'}]
{'name': 'Ada Lovelace'}
[{'name': 'Ada Lovelace'}]
{'name': 'Alan Turing'}
[{'name': 'Alan Turing'}, {'name': 'Alan Turing'}]
You are reusing the same dictionary over and over again. Create a new dictionary in the loop instead:
for i in a:
c = {'name': i}
d.append(c)
Appending an object to a list does not create a copy; it merely stores a reference to that object in the list.
By re-using the same dict object over and over again, you are merely appending multiple references to one dictionary to the list.
Using the dictionary literal syntax, along with a list comprehension will do what you need:
>>> names = ['foo','bar']
>>> d = [{'name': i} for i in names]
>>> d
[{'name': 'foo'}, {'name': 'bar'}]

Categories