Dictionary list raised a key error in Python - python

I have a list of dictionary, and I would like to count the values for keys of "increasing" and "decreasing" respectively. My script returned a key error that might because not all dictionaries have "increasing" and "decreasing" both. But I have no idea how to fix it. As a Python beginner, any help would be appreciated.
list_of_dicts = [{"decreasing": 1}, {"increasing": 4}, {"decreasing": 1}, {"increasing": 3},{"decreasing": 1},
{"increasing": 1}]
values1 = [a_dict["decreasing"] for a_dict in list_of_dicts]
values2 = [a_dict["increasing"] for a_dict in list_of_dicts]
print(values1)
print(values2)
The expected result is:
[1,1,1]
[4,3,1]

You can use sum() + dict.get with default value 0:
values1 = sum(d.get("increasing", 0) for d in list_of_dicts)
values2 = sum(d.get("decreasing", 0) for d in list_of_dicts)
print("Increasing:", values1)
print("Decreasing:", values2)
Prints:
Increasing: 29
Decreasing: 9
EDIT: To get values:
values1, values2 = [], []
for d in list_of_dicts:
if "increasing" in d:
values1.append(d["increasing"])
elif "decreasing" in d:
values2.append(d["decreasing"])
print("Increasing:", values1)
print("Decreasing:", values2)
Prints:
Increasing: [4, 3, 1, 5, 11, 1, 4]
Decreasing: [1, 1, 1, 1, 2, 1, 2]

Add an if in the list comprehension, that'll keep the good ones
values1 = [a_dict["decreasing"] for a_dict in list_of_dicts if "decreasing" in a_dict]
values2 = [a_dict["increasing"] for a_dict in list_of_dicts if "increasing" in a_dict]
print(values1) # [1, 1, 1, 1, 2, 1, 2]
print(values2) # [4, 3, 1, 5, 11, 1, 4]

When working with list comprehensions that are having issues, break them down.
First it can be broken down into:
values1 = list()
for a_dict in list_of_dicts:
if a_dict.get('decreasing'):
values1.append(a_dict.get('decreasing'))
values2 = list()
for a_dict in list_of_dicts:
if a_dict.get('increasing'):
values2.append(a_dict.get('increasing'))
Then bring them back up into the comprehension.
list_of_dicts = [{"decreasing": 1}, {"increasing": 4}, {"decreasing": 1}, {"increasing": 3},{"decreasing": 1},
{"increasing": 1},{"decreasing": 1}, {"increasing": 5}, {"decreasing": 2}, {"increasing": 11},
{"decreasing": 1}, {"increasing": 1},{"decreasing": 2}, {"increasing": 4}]
values1 = [a_dict.get('decreasing') for a_dict in list_of_dicts if a_dict.get('decreasing')]
values2 = [a_dict.get('increasing') for a_dict in list_of_dicts if a_dict.get('increasing')]
values11 = list()
for a_dict in list_of_dicts:
if a_dict.get('decreasing'):
values11.append(a_dict.get('decreasing'))
values22 = list()
for a_dict in list_of_dicts:
if a_dict.get('increasing'):
values22.append(a_dict.get('increasing'))
print(values1)
print(values2)
print(values1 == values11)
print(values2 == values22)
Results in
$ python testing.py
[1, 1, 1, 1, 2, 1, 2]
[4, 3, 1, 5, 11, 1, 4]
True
True

Related

Python Dictionary Filtration with items as a list

I have several lists as items in my dictionary. I want to create a dictionary with the same keys, but only with items that correspond to the unique values of the list in the first key. What's the best way to do this?
Original:
d = {'s': ['a','a','a','b','b','b','b'],
'd': ['c1','d2','c3','d4','c5','d6','c7'],
'g': ['e1','f2','e3','f4','e5','f6','e7']}
Output:
e = {'s': ['a','a','a'],
'd': ['c1','d2','c3'],
'g': ['e1','f2','e3']}
f = {'s': ['b','b','b','b'],
'd': ['d4','c5','d6','c7'],
'g': ['f4','e5','f6','e7']}
I don't think there is an easy way to do this. I created a (not so) little function for you:
def func(entry):
PARSING_KEY = "s"
# check if entry dict is valid (optional)
assert type(entry)==dict
for key in entry.keys():
assert type(entry[key])==list
first_list = entry[PARSING_KEY]
first_list_len = len(first_list)
for key in entry.keys():
assert len(entry[key]) == first_list_len
# parsing
output_list_index = []
already_check = set()
for index1, item1 in enumerate(entry[PARSING_KEY]):
if not item1 in already_check:
output_list_index.append([])
for index2, item2 in enumerate(entry[PARSING_KEY][index1:]):
if item2==item1:
output_list_index[-1].append(index2)
already_check.add(item1)
# creating lists
output_list = []
for indexes in output_list_index:
new_dict = {}
for key, value in entry.items():
new_dict[key] = [value[i] for i in indexes]
output_list.append(new_dict)
return output_list
Note that because of the structure of dict, there isn't a "first key" so you have to hardcode the key you want to use to parse (whit the "PARSING_KEY" constant at the top of the function)
original_dict = {
'a': [1, 3, 5, 8, 4, 2, 1, 2, 7],
'b': [4, 4, 4, 4, 4, 3],
'c': [822, 1, 'hello', 'world']
}
distinct_dict = {k: list(set(v)) for k, v in original_dict.items()}
distinct_dict
yields
{'a': [1, 2, 3, 4, 5, 7, 8], 'b': [3, 4], 'c': [1, 'hello', 'world', 822]}

merge two lists into dictionary

I'm trying to merge two lists to dict:
l1 = [1, 3, 6, 0, 1, 1]
l2 = ['foo1', 'foo2', 'foo1', 'foo2', 'foo2', 'bar1']
I'd like to get:
list = [{"foo1": 1},
{"foo2": 3},
{"foo1": 6},
{"foo2": 0},
{"foo2": 1},
{"bar1": 1},]
trying to use zip but get an error :"<zip object at 0x000>"
You can try this:
l1 = [1, 3, 6, 0, 1, 1]
l2 = ['foo1', 'foo2', 'foo1', 'foo2', 'foo2', 'bar1']
data = [{k: v} for k, v in zip(l2, l1)]
print(data)
Output:
[{'foo1': 1}, {'foo2': 3}, {'foo1': 6}, {'foo2': 0}, {'foo2': 1}, {'bar1': 1}]
I wouldn't consider this an ideal data structure though, unless you have a lot more data in the individual dictionaries.
The answer by #Tenacious B achieves what you requested.
You might, however, be better with a dictionary of lists. The keys would be items from l2 and values would be a list containing the corresponding values from l1. A collections.defaultdict makes this easy:
l1 = [1, 3, 6, 0, 1, 1]
l2 = ['foo1', 'foo2', 'foo1', 'foo2', 'foo2', 'bar1']
from collections import defaultdict
d = defaultdict(list)
for k, v in zip(l2, l1):
d[k].append(v)
print(d)
Output:
defaultdict(, {'foo1': [1, 6], 'foo2': [3, 0, 1], 'bar1': [1]})
Now you can access the data by key:
>>> d['foo2']
[3, 0, 1]
>>> d['foo1']
[1, 6]
I'm pretty sure <zip object at 0x0000021A9C9F71C0> is not an error, you just haven't execute the code yet. It is stored in a zip object which is waiting for execution.

Populating a nested dictionary with a simple list

I have a list = [1,2,3,4,5] which I want to populate into a dictionary but my dict is currently
my_dict={a:none,b:[none,none,none],c:none}
Required output: {a: 1, b: [2,3,4], c: 5}
my_list = [1,2,3,4,5]
my_dict = {'a': None,'b': [None, None, None],'c': None}
for key in my_dict.keys():
if my_dict[key] == None:
my_dict[key] = my_list[0]
my_list.pop(0)
else:
if type(my_dict[key]) is list:
for item in range(len(my_dict[key])):
if my_dict[key][item] == None:
my_dict[key][item] = my_list[0]
my_list.pop(0)
print(my_dict)
Output:
{'a': 1, 'b': [2, 3, 4], 'c': 5}
This code segment assigns the first element to a, the last element to c, and all intermediate elements are assigned to b.
lis = [1,2,3,4,5]
output = {'a': lis[0], 'b': lis[1:len(lis)-1], 'c': lis[len(lis)-1]}
print(output)
Output:
{'a': 1, 'b': [2, 3, 4], 'c': 5}

Combining dictionaries within dictionaries & adding values

I am trying to combine two dictionaries to yield a result like this:
a = {"cat": 3, "dog": 4, "rabbit": 19, "horse": 3, "shoe": 2}
b = {"cat": 2, "rabbit": 1, "fish": 9, "horse": 5}
ab = {"cat": 5, "dog": 4, "rabbit": 20, "horse": 8, "shoe": 2, "fish": 9}
So that if they have the same keys, the values will be added, if one key is present in one dictionary but not the other, it will add it to the new dictionary with its corresponding value.
These two dictionaries are also both nested in separate dictionaries as well such that:
x = {'a': {"cat": 3, "dog": 4, "rabbit": 19, "horse": 3, "shoe": 2}, 'c': blah, 'e': fart}
y = {'a': {"cat": 2, "rabbit": 1, "fish": 9, "horse": 5}, 'c': help, 'e': me}
The keys are the same in both main dictionaries.
I have been trying to combine the two dictionaries:
def newdict(x,y):
merged= [x,y]
newdict = {}
for i in merged:
for k,v in i.items():
new.setdefault(k,[]).append(v)
All this gives me is a dictionary with values belonging to the same keys in a list. I can't figure out how to iterate through the two lists for a key and add the values together to create one joint dictionary. Can anyone help me?
End result should be something like:
xy = {'a' = {"cat": 5, "dog": 4, "rabbit": 20, "horse": 8, "shoe": 2, "fish": 9}, 'c': blah, 'e': me}
The 'c' and 'e' keys I will have to iterate through and perform a different calculation based on the results from 'a'.
I hope I explained my problem clearly enough.
My attempt would be:
a = {"cat": 3, "dog": 4, "rabbit": 19, "horse": 3, "shoe": 2}
b = {"cat": 2, "rabbit": 1, "fish": 9, "horse": 5}
def newdict(x, y):
ret = {}
for key in x.keys():
if isinstance(x[key], dict):
ret[key] = newdict(x[key], y.get(key, {}))
continue
ret[key] = x[key] + y.get(key, 0)
for key in y.keys():
if isinstance(y[key], dict):
ret[key] = newdict(y[key], x.get(key, {}))
continue
ret[key] = y[key] + x.get(key, 0)
return ret
ab = newdict(a, b)
print ab
> {'horse': 8, 'fish': 9, 'dog': 4, 'cat': 5, 'shoe': 2, 'rabbit': 20}
Explanation:
The newdict function first iterates through the first dictionary (x). For every key in x, it creates a new entry in the new dictionary, setting the value to the sum of x[key] and y[key]. The dict.get function supplies an optional second argument that it returns when key isn't in dict.
If x[key] is a dict, it sets ret[key] to a merged dictionary of x[key] and y[key].
It then does the same for y and returns.
Note: This doesn't work for functions. Try figuring something out yourself there.
Using collections.Counter and isinstance:
>>> from collections import Counter
>>> from itertools import chain
>>> x = {'e': 'fart', 'a': {'dog': 4, 'rabbit': 19, 'shoe': 2, 'cat': 3, 'horse': 3}, 'c': 'blah'}
>>> y = {'e': 'me', 'a': {'rabbit': 1, 'fish': 9, 'cat': 2, 'horse': 5}, 'c': 'help'}
>>> c = {}
>>> for k, v in chain(x.items(), y.items()):
if isinstance(v, dict):
c[k] = c.get(k, Counter()) + Counter(v)
...
>>> c
{'a': Counter({'rabbit': 20, 'fish': 9, 'horse': 8, 'cat': 5, 'dog': 4, 'shoe': 2})}
Now based on the value of 'a' you can calculate the values for keys 'a' and 'e', but this time use: if not isinstance(v, dict)
Update: Solution using no imports:
>>> c = {}
>>> for d in (x, y):
for k, v in d.items():
if isinstance(v, dict):
keys = (set(c[k]) if k in c else set()).union(set(v)) #Common keys
c[k] = { k1: v.get(k1, 0) + c.get(k, {}).get(k1, 0) for k1 in keys}
...
>>> c
{'a': {'dog': 4, 'rabbit': 20, 'shoe': 2, 'fish': 9, 'horse': 8, 'cat': 5}}
To do it easily, you can use collections.Counter:
>>> from collections import Counter
>>> a = {"cat": 3, "dog": 4, "rabbit": 19, "horse": 3, "shoe": 2}
>>> b = {"cat": 2, "rabbit": 1, "fish": 9, "horse": 5}
>>> Counter(a) + Counter(b)
Counter({'rabbit': 20, 'fish': 9, 'horse': 8, 'cat': 5, 'dog': 4, 'shoe': 2})
So, in your case, it would be something like:
newdict['a'] = Counter(x['a']) + Counter(y['a'])
If you for some reason don't want it to be a Counter, you just pass the result to dict().
Edit:
If you're not allowed imports, you'll have to do the addition manually, but this should be simple enough.
Since this sounds like homework, I'll give you a few hints instead of a full answer:
create a collection of all keys, or loop over each dict(you can use a set to make sure the keys are unique, but duplicates shouldn't be a problem, since they'll be overwritten)
for each key, add the sum of values in the old dicts to the new dict(you can use dict.get() to get a 0 if the key is not present)
def newDict(a,b):
newD={}
for key in a:
newD[key]=a[key]
for key in b:
newD[key]=newD.get(key,0)+b[key]
return newD
My naive solution is:
a = {'a':'b'}
b = {'c':'d'}
c = {'e':'f'}
def Merge(n):
m = {}
for i in range(len(n)):
m.update({i+1:n[i]})
return m
print(Merge([a,b,c]))

List of dicts to/from dict of lists

I want to change back and forth between a dictionary of (equal-length) lists:
DL = {'a': [0, 1], 'b': [2, 3]}
and a list of dictionaries:
LD = [{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
For those of you that enjoy clever/hacky one-liners.
Here is DL to LD:
v = [dict(zip(DL,t)) for t in zip(*DL.values())]
print(v)
and LD to DL:
v = {k: [dic[k] for dic in LD] for k in LD[0]}
print(v)
LD to DL is a little hackier since you are assuming that the keys are the same in each dict. Also, please note that I do not condone the use of such code in any kind of real system.
If you're allowed to use outside packages, Pandas works great for this:
import pandas as pd
pd.DataFrame(DL).to_dict(orient="records")
Which outputs:
[{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
You can also use orient="list" to get back the original structure
{'a': [0, 1], 'b': [2, 3]}
Perhaps consider using numpy:
import numpy as np
arr = np.array([(0, 2), (1, 3)], dtype=[('a', int), ('b', int)])
print(arr)
# [(0, 2) (1, 3)]
Here we access columns indexed by names, e.g. 'a', or 'b' (sort of like DL):
print(arr['a'])
# [0 1]
Here we access rows by integer index (sort of like LD):
print(arr[0])
# (0, 2)
Each value in the row can be accessed by column name (sort of like LD):
print(arr[0]['b'])
# 2
To go from the list of dictionaries, it is straightforward:
You can use this form:
DL={'a':[0,1],'b':[2,3], 'c':[4,5]}
LD=[{'a':0,'b':2, 'c':4},{'a':1,'b':3, 'c':5}]
nd={}
for d in LD:
for k,v in d.items():
try:
nd[k].append(v)
except KeyError:
nd[k]=[v]
print nd
#{'a': [0, 1], 'c': [4, 5], 'b': [2, 3]}
Or use defaultdict:
nd=cl.defaultdict(list)
for d in LD:
for key,val in d.items():
nd[key].append(val)
print dict(nd.items())
#{'a': [0, 1], 'c': [4, 5], 'b': [2, 3]}
Going the other way is problematic. You need to have some information of the insertion order into the list from keys from the dictionary. Recall that the order of keys in a dict is not necessarily the same as the original insertion order.
For giggles, assume the insertion order is based on sorted keys. You can then do it this way:
nl=[]
nl_index=[]
for k in sorted(DL.keys()):
nl.append({k:[]})
nl_index.append(k)
for key,l in DL.items():
for item in l:
nl[nl_index.index(key)][key].append(item)
print nl
#[{'a': [0, 1]}, {'b': [2, 3]}, {'c': [4, 5]}]
If your question was based on curiosity, there is your answer. If you have a real-world problem, let me suggest you rethink your data structures. Neither of these seems to be a very scalable solution.
Here are the one-line solutions (spread out over multiple lines for readability) that I came up with:
if dl is your original dict of lists:
dl = {"a":[0, 1],"b":[2, 3]}
Then here's how to convert it to a list of dicts:
ld = [{key:value[index] for key,value in dl.items()}
for index in range(max(map(len,dl.values())))]
Which, if you assume that all your lists are the same length, you can simplify and gain a performance increase by going to:
ld = [{key:value[index] for key, value in dl.items()}
for index in range(len(dl.values()[0]))]
Here's how to convert that back into a dict of lists:
dl2 = {key:[item[key] for item in ld]
for key in list(functools.reduce(
lambda x, y: x.union(y),
(set(dicts.keys()) for dicts in ld)
))
}
If you're using Python 2 instead of Python 3, you can just use reduce instead of functools.reduce there.
You can simplify this if you assume that all the dicts in your list will have the same keys:
dl2 = {key:[item[key] for item in ld] for key in ld[0].keys() }
cytoolz.dicttoolz.merge_with
Docs
from cytoolz.dicttoolz import merge_with
merge_with(list, *LD)
{'a': [0, 1], 'b': [2, 3]}
Non-cython version
Docs
from toolz.dicttoolz import merge_with
merge_with(list, *LD)
{'a': [0, 1], 'b': [2, 3]}
The python module of pandas can give you an easy-understanding solution. As a complement to #chiang's answer, the solutions of both D-to-L and L-to-D are as follows:
import pandas as pd
DL = {'a': [0, 1], 'b': [2, 3]}
out1 = pd.DataFrame(DL).to_dict('records')
Output:
[{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
In the other direction:
LD = [{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
out2 = pd.DataFrame(LD).to_dict('list')
Output:
{'a': [0, 1], 'b': [2, 3]}
Cleanest way I can think of a summer friday. As a bonus, it supports lists of different lengths (but in this case, DLtoLD(LDtoDL(l)) is no more identity).
From list to dict
Actually less clean than #dwerk's defaultdict version.
def LDtoDL (l) :
result = {}
for d in l :
for k, v in d.items() :
result[k] = result.get(k,[]) + [v] #inefficient
return result
From dict to list
def DLtoLD (d) :
if not d :
return []
#reserve as much *distinct* dicts as the longest sequence
result = [{} for i in range(max (map (len, d.values())))]
#fill each dict, one key at a time
for k, seq in d.items() :
for oneDict, oneValue in zip(result, seq) :
oneDict[k] = oneValue
return result
I needed such a method which works for lists of different lengths (so this is a generalization of the original question). Since I did not find any code here that the way that I expected, here's my code which works for me:
def dict_of_lists_to_list_of_dicts(dict_of_lists: Dict[S, List[T]]) -> List[Dict[S, T]]:
keys = list(dict_of_lists.keys())
list_of_values = [dict_of_lists[key] for key in keys]
product = list(itertools.product(*list_of_values))
return [dict(zip(keys, product_elem)) for product_elem in product]
Examples:
>>> dict_of_lists_to_list_of_dicts({1: [3], 2: [4, 5]})
[{1: 3, 2: 4}, {1: 3, 2: 5}]
>>> dict_of_lists_to_list_of_dicts({1: [3, 4], 2: [5]})
[{1: 3, 2: 5}, {1: 4, 2: 5}]
>>> dict_of_lists_to_list_of_dicts({1: [3, 4], 2: [5, 6]})
[{1: 3, 2: 5}, {1: 3, 2: 6}, {1: 4, 2: 5}, {1: 4, 2: 6}]
>>> dict_of_lists_to_list_of_dicts({1: [3, 4], 2: [5, 6], 7: [8, 9, 10]})
[{1: 3, 2: 5, 7: 8},
{1: 3, 2: 5, 7: 9},
{1: 3, 2: 5, 7: 10},
{1: 3, 2: 6, 7: 8},
{1: 3, 2: 6, 7: 9},
{1: 3, 2: 6, 7: 10},
{1: 4, 2: 5, 7: 8},
{1: 4, 2: 5, 7: 9},
{1: 4, 2: 5, 7: 10},
{1: 4, 2: 6, 7: 8},
{1: 4, 2: 6, 7: 9},
{1: 4, 2: 6, 7: 10}]
Here my small script :
a = {'a': [0, 1], 'b': [2, 3]}
elem = {}
result = []
for i in a['a']: # (1)
for key, value in a.items():
elem[key] = value[i]
result.append(elem)
elem = {}
print result
I'm not sure that is the beautiful way.
(1) You suppose that you have the same length for the lists
Here is a solution without any libraries used:
def dl_to_ld(initial):
finalList = []
neededLen = 0
for key in initial:
if(len(initial[key]) > neededLen):
neededLen = len(initial[key])
for i in range(neededLen):
finalList.append({})
for i in range(len(finalList)):
for key in initial:
try:
finalList[i][key] = initial[key][i]
except:
pass
return finalList
You can call it as follows:
dl = {'a':[0,1],'b':[2,3]}
print(dl_to_ld(dl))
#[{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
If you don't mind a generator, you can use something like
def f(dl):
l = list((k,v.__iter__()) for k,v in dl.items())
while True:
d = dict((k,i.next()) for k,i in l)
if not d:
break
yield d
It's not as "clean" as it could be for Technical Reasons: My original implementation did yield dict(...), but this ends up being the empty dictionary because (in Python 2.5) a for b in c does not distinguish between a StopIteration exception when iterating over c and a StopIteration exception when evaluating a.
On the other hand, I can't work out what you're actually trying to do; it might be more sensible to design a data structure that meets your requirements instead of trying to shoehorn it in to the existing data structures. (For example, a list of dicts is a poor way to represent the result of a database query.)
List of dicts ⟶ dict of lists
from collections import defaultdict
from typing import TypeVar
K = TypeVar("K")
V = TypeVar("V")
def ld_to_dl(ld: list[dict[K, V]]) -> dict[K, list[V]]:
dl = defaultdict(list)
for d in ld:
for k, v in d.items():
dl[k].append(v)
return dl
defaultdict creates an empty list if one does not exist upon key access.
Dict of lists ⟶ list of dicts
Collecting into "jagged" dictionaries
from typing import TypeVar
K = TypeVar("K")
V = TypeVar("V")
def dl_to_ld(dl: dict[K, list[V]]) -> list[dict[K, V]]:
ld = []
for k, vs in dl.items():
ld += [{} for _ in range(len(vs) - len(ld))]
for i, v in enumerate(vs):
ld[i][k] = v
return ld
This generates a list of dictionaries ld that may be missing items if the lengths of the lists in dl are unequal. It loops over all key-values in dl, and creates empty dictionaries if ld does not have enough.
Collecting into "complete" dictionaries only
(Usually intended only for equal-length lists.)
from typing import TypeVar
K = TypeVar("K")
V = TypeVar("V")
def dl_to_ld(dl: dict[K, list[V]]) -> list[dict[K, V]]:
ld = [dict(zip(dl.keys(), v)) for v in zip(*dl.values())]
return ld
This generates a list of dictionaries ld that have the length of the smallest list in dl.
DL={'a':[0,1,2,3],'b':[2,3,4,5]}
LD=[{'a':0,'b':2},{'a':1,'b':3}]
Empty_list = []
Empty_dict = {}
# to find length of list in values of dictionry
len_list = 0
for i in DL.values():
if len_list < len(i):
len_list = len(i)
for k in range(len_list):
for i,j in DL.items():
Empty_dict[i] = j[k]
Empty_list.append(Empty_dict)
Empty_dict = {}
LD = Empty_list

Categories

Resources