I am trying to build a dict from a set of unique values to serve as the keys and a zipped list of tuples to provide the items.
set = ("a","b","c")
lst 1 =("a","a","b","b","c","d","d")
lst 2 =(1,2,3,3,4,5,6,)
zip = [("a",1),("a",2),("b",3),("b",3),("c",4),("d",5)("d",6)
dct = {"a":1,2 "b":3,3 "c":4 "d":5,6}
But I am getting:
dct = {"a":1,"b":3,"c":4,"d":5}
here is my code so far:
#make two lists
rtList = ["EVT","EVT","EVT","EVT","EVT","EVT","EVT","HIL"]
raList = ["C64G","C64R","C64O","C32G","C96G","C96R","C96O","RA96O"]
# make a set of unique codes in the first list
routes = set()
for r in rtList:
routes.add(r)
#zip the lists
RtRaList = zip(rtList,raList)
#print RtRaList
# make a dictionary with list one as the keys and list two as the values
SrvCodeDct = {}
for key, item in RtRaList:
for r in routes:
if r == key:
SrvCodeDct[r] = item
for key, item in SrvCodeDct.items():
print key, item
You don't need any of that. Just use a collections.defaultdict.
import collections
rtList = ["EVT","EVT","EVT","EVT","EVT","EVT","EVT","HIL"]
raList = ["C64G","C64R","C64O","C32G","C96G","C96R","C96O","RA96O"]
d = collections.defaultdict(list)
for k,v in zip(rtList, raList):
d[k].append(v)
You may achieve this using dict.setdefault method as:
my_dict = {}
for i, j in zip(l1, l2):
my_dict.setdefault(i, []).append(j)
which will return value of my_dict as:
>>> my_dict
{'a': [1, 2], 'c': [4], 'b': [3, 3], 'd': [5, 6]}
OR, use collections.defaultdict as mentioned by TigerhawkT3.
Issue with your code: You are not making the check for existing key. Everytime you do SrvCodeDct[r] = item, you are updating the previous value of r key with item value. In order to fix this, you have to add if condition as:
l1 = ("a","a","b","b","c","d","d")
l2 = (1,2,3,3,4,5,6,)
my_dict = {}
for i, j in zip(l1, l2):
if i in my_dict: # your `if` check
my_dict[i].append(j) # append value to existing list
else:
my_dict[i] = [j]
>>> my_dict
{'a': [1, 2], 'c': [4], 'b': [3, 3], 'd': [5, 6]}
However this code can be simplified using collections.defaultdict (as mentioned by TigerhawkT3), OR using dict.setdefault method as:
my_dict = {}
for i, j in zip(l1, l2):
my_dict.setdefault(i, []).append(j)
In dicts, all keys are unique, and each key can only have one value.
The easiest way to solve this is have the value of the dictionary be a list, as to emulate what is called a multimap. In the list, you have all the elements that is mapped-to by the key.
EDIT:
You might want to check out this PyPI package: https://pypi.python.org/pypi/multidict
Under the hood, however, it probably works as described above.
Afaik, there is nothing built-in that supports what you are after.
Related
Say I have a list of dict:
ld = [{'a':1,'b':2,'c':9},{'a':1,'b':2,'c':10}]
And a list to filter the keys out:
l = ['a','c']
Want to remove key a and c from ld:
Try:
result = [d for d in ld for k in d if k in l]
Desired Result:
[{'b':2},{'b':2}]
Your outer container needs to be a list : use a (1 dimension) list comprehension
Your inner container needs to be a dict : ues a dict comprehension
For you now you're using a 2d list comprehension
The filtering part should be at the dict level
ld = [{'a': 1, 'b': 2, 'c': 9}, {'a': 1, 'b': 2, 'c': 10}]
l = ['a', 'c']
result = [{k: v for k, v in subdict.items() if k not in l}
for subdict in ld]
print(result)
Your code is overly compressed and that makes it hard to understand and easy for bugs to hide.
Here you want to "filter" a list of dicts and remove entries from each dicht that is not in the filter list. So my first suggestion is to rename your variables:
data = [{'a': 1, 'b': 2, 'c': 9}, {'a': 1, 'b': 2, 'c': 10}]
excludes = ['a', 'c']
Now you need to unpack a list, and then the inner dict. Currently you are trying to use the list iteration on both. You want items() to iterate over (key, value) pairs.
Further, you are filtering on the outer list level, while the keys to filter live in the inner dict.
Here is my solution
result = []
for entry in data:
# entry is now one of the dicts
result.append({key:value for key, value in entry.items() if key not in excludes})
You can compress this again in a single line, if you really want to. But in my opinion (while not playing code golf) readability beats compressedness.
I think the simple writing method is clearer when there are many cycles
ld = [{'a':1,'b':2,'c':9},{'a':1,'b':2,'c':10}]
l = ['a','c']
for d in ld:
for r in l:
if r in d:
del d[r]
Alternative filtering whether keys in ld are not in l:
result = [{k:d[k]} for d in ld for k in d if k not in l]
I still have a solution but wonder if there is a more pythonic version with in-built Python tools.
The goal would be to avoid the for loop.
Does Python offer a technique (package) to solve this?
I have 2 lists of the same length, one representing keys (with possible duplicates) and the other the values.
keys = list('ABAA')
vals = [1, 2, 1, 3]
The expected result:
{
'A': [1, 1, 3],
'B': [2]
}
My working solution (with Python 3.9):
result = {}
for k, v in zip(keys, vals):
# create new entry with empty list
if k not in result:
result[k] = []
# store the value
result[k].append(v)
print(result)
Very similar to your solution (which is great btw), but you could zip the lists and use dict.setdefault:
out = {}
for k,v in zip(keys,vals):
out.setdefault(k, []).append(v)
Output:
{'A': [1, 1, 3], 'B': [2]}
Can use this:
keys = list('ABAA')
vals = [1, 2, 1, 3]
d = {}
for key in set(keys):
d[key] = [vals[i] for i in range(len(keys)) if keys[i] == key]
So my input values are as follows:
temp_dict1 = {'A': [1,2,3,4], 'B':[5,5,5], 'C':[6,6,7,8]}
temp_dict2 = {}
val = [5]
The list val may contain more values, but for now, it only contains one. My desired outcome is:
>>>temp_dict2
{'B':[5]}
The final dictionary needs to only have the keys for the lists that contain the item in the list val, and only unique instances of that value in the list. I've tried iterating through the two objects as follows:
for i in temp_dict1:
for j in temp_dict1[i]:
for k in val:
if k in j:
temp_dict2.setdefault(i, []).append(k)
But that just returns an argument of type 'int' is not iterable error message. Any ideas?
Changed your dictionary to cover some more cases:
temp_dict1 = {'A': [1,2,3,4], 'B':[5,5,6], 'C':[6,6,7,8]}
temp_dict2 = {}
val = [5, 6]
for item in val:
for key, val in temp_dict1.items():
if item in val:
temp_dict2.setdefault(key, []).append(item)
print(temp_dict2)
# {'B': [5, 6], 'C': [6]}
Or, the same using list comprehension (looks a bit hard to understand, not recommended).
temp_dict2 = {}
[temp_dict2.setdefault(key, []).append(item) for item in val for key, val in temp_dict1.items() if item in val]
For comparison with #KeyurPotdar's solution, this can also be achieved via collections.defaultdict:
from collections import defaultdict
temp_dict1 = {'A': [1,2,3,4], 'B':[5,5,6], 'C':[6,6,7,8]}
temp_dict2 = defaultdict(list)
val = [5, 6]
for i in val:
for k, v in temp_dict1.items():
if i in v:
temp_dict2[k].append(i)
# defaultdict(list, {'B': [5, 6], 'C': [6]})
You can try this approach:
temp_dict1 = {'A': [1,2,3,4,5,6], 'B':[5,5,5], 'C':[6,6,7,8]}
val = [5,6]
def values(dict_,val_):
default_dict={}
for i in val_:
for k,m in dict_.items():
if i in m:
if k not in default_dict:
default_dict[k]=[i]
else:
default_dict[k].append(i)
return default_dict
print(values(temp_dict1,val))
output:
{'B': [5], 'C': [6], 'A': [5, 6]}
I'm trying to only add keys with a value >= n to my list, however I can't give the key an argument.
n = 2
dict = {'a': 1, 'b': 2, 'c': 3}
for i in dict:
if dict[i] >= n:
list(dict.keys([i])
When I try this, it tells me I can't give .keys() an argument. But if I remove the argument, all keys are added, regardless of value
Any help?
You don't need to call .keys() method of dict as you are already iterating data_dict's keys using for loop.
n = 2
data_dict = {'a': 1, 'b': 2, 'c': 3}
lst = []
for i in data_dict:
if data_dict[i] >= n:
lst.append(i)
print lst
Results:
['c', 'b']
You can also achieve this using list comprehension
result = [k for k, v in data_dict.iteritems() if v >= 2]
print result
You should read this: Iterating over Dictionaries.
Try using filter:
filtered_keys = filter(lambda x: d[x] >= n, d.keys())
Or using list comprehension:
filtered_keys = [x for x in d.keys() if d[x] >= n]
The error in your code is that dict.keys returns all keys, as the docs mention:
Return a copy of the dictionary’s list of keys.
What you want is one key at a time, which list comprehension gives you. Also, when filtering, which is basically what you do, consider using the appropriate method (filter).
Let's say I have the following list of python dictionary:
dict1 = [{'domain':'Ratios'},{'domain':'Geometry'}]
and a list like:
list1 = [3, 6]
I'd like to update dict1 or create another list as follows:
dict1 = [{'domain':'Ratios', 'count':3}, {'domain':'Geometry', 'count':6}]
How would I do this?
>>> l1 = [{'domain':'Ratios'},{'domain':'Geometry'}]
>>> l2 = [3, 6]
>>> for d,num in zip(l1,l2):
d['count'] = num
>>> l1
[{'count': 3, 'domain': 'Ratios'}, {'count': 6, 'domain': 'Geometry'}]
Another way of doing it, this time with a list comprehension which does not mutate the original:
>>> [dict(d, count=n) for d, n in zip(l1, l2)]
[{'count': 3, 'domain': 'Ratios'}, {'count': 6, 'domain': 'Geometry'}]
You could do this:
for i, d in enumerate(dict1):
d['count'] = list1[i]
You can do this:
# list index
l_index=0
# iterate over all dictionary objects in dict1 list
for d in dict1:
# add a field "count" to each dictionary object with
# the appropriate value from the list
d["count"]=list1[l_index]
# increase list index by one
l_index+=1
This solution doesn't create a new list. Instead, it updates the existing dict1 list.
Using list comprehension will be the pythonic way to do it.
[data.update({'count': list1[index]}) for index, data in enumerate(dict1)]
The dict1 will be updated with the corresponding value from list1.