How to cast a list to a dictionary - python

I have a list as a input made from tuples where the origin is the 1st object and the neighbour is the 2nd object of the tuple.
for example :
inp : lst = [('a','b'),('b','a'),('c',''),('a','c')]
out : {'a': ('a', ['b', 'c']), 'b': ('b', ['a']), 'c': ('c', [])}
first i tried to cast the list into a dictonary,
like this
dictonary = dict(lst)
but i got an error say that
dictionary update sequence element #0 has length 1; 2 is required

The simplest is probably inside a try / except block:
lst = [('a','b'),('b','a'),('c',''),('a','c')]
out = dict()
for k, v in lst:
try:
if v != '':
out[k][1].append(v)
else:
out[k][1].append([])
except KeyError:
if v != '':
out[k] = (k, [v])
else:
out[k] = (k, [])
print out
Which gives:
{'a': ('a', ['b', 'c']), 'b': ('b', ['a']), 'c': ('c', [])}

Here's how I did it, gets the result you want, you can blend the two operations into the same loop, make a function out of it etc, have fun! Written without Python one liners kung-fu for beginner friendliness!
>>> lst = [('a','b'),('b','a'),('c',''),('a','c')]
>>> out = {}
>>> for pair in lst:
... if pair[0] not in out:
... out[pair[0]] = (pair[0], [])
...
>>> out
{'a': ('a', []), 'c': ('c', []), 'b': ('b', [])}
>>> for pair in lst:
... out[pair[0]][1].append(pair[1])
...
>>> out
{'a': ('a', ['b', 'c']), 'c': ('c', ['']), 'b': ('b', ['a'])}

Just here to mention setdefault
lst = [('a','b'),('b','a'),('c',''),('a','c')]
d = {}
for first, second in lst:
tup = d.setdefault(first, (first, []))
if second and second not in tup[1]:
tup[1].append(second)

Related

How to format a list which has two elements

list = [(a, 59.34), (t, 56.54), (d, 34.74), (u, 5.89)]
The list is descending order of the number(the second element)
I would like to format them like below.
a: 59.34
t: 56.54
d: 34.74
u: 5.89
details = []
for item in list:
name = item[0]
num = item[2]
details.append(f"{name}: {num:.2f}")
lst = [('a', 59.34), ('t', 56.54), ('d', 34.74), ('u', 5.89)]
details = [f"{x[0]}: {x[1]:.2f}" for x in lst]
print(*details, sep='\n')
Prints:
a: 59.34
t: 56.54
d: 34.74
u: 5.89
Looks like you want to convert the list to a dictionary. You can use dictionary comprehension to iterate through the list and convert the tuple(key, value) into key: value
list1 = [('a', 59.34), ('t', 56.54), ('d', 34.74), ('u', 5.89)]
dict_from_list = {key: val for (key, val) in list1}
print(dict_from_list)
# {'a': 59.34, 't': 56.54, 'd': 34.74, 'u': 5.89}
lst = [('a', 59.34), ('t', 56.54), ('d', 34.74), ('u', 5.89)]
list_comp = [f"{i[0]}: {i[-1]}" for i in lst]
print(list_comp)
(Ans)
['a: 59.34', 't: 56.54', 'd: 34.74', 'u: 5.89']
(Or )
for j in lst:
print(f"{j[0]}: {j[-1]}")
(Ans)
a: 59.34
t: 56.54
d: 34.74
u: 5.89
You could use a dictionary comprehension as your list already has elements as pairs therefore you have to just do the following:
items = [('a', 59.34), ('t', 56.54), ('d', 34.74), ('u', 5.89)] # try not to use the built-in method names or keywords as variable names
details = {k:v for k,v in items} # it uses the first element of the tuple as key and seocnd as a value
print(details)
Would output:
{'a': 59.34, 't': 56.54, 'd': 34.74, 'u': 5.89}
You could also use a loop:
items = [('a', 59.34), ('t', 56.54), ('d', 34.74), ('u', 5.89)]
details = {}
for i in items:
details[i[0]] = i[1]
print(details)
Would result in:
{'a': 59.34, 't': 56.54, 'd': 34.74, 'u': 5.89}

How to access/assert tuple key values in a python dictionary

How can I return "True" or "False" if 2 consecutive strings are in a dictionary key that is a tuple/triple?
d = {(1, 'a', 'b') : 2, (4, 'c', 'd'):5}
I need an expression like:
return 'a', 'b' in d.keys()
You can do it with nested for loops:
def myFunc(myDict):
myKeys = list(myDict.keys())
for myList in myKeys:
myPreviousElement = None
for myElement in myList:
if myElement == myPreviousElement:
return True
myPreviousElement = myElement
return False
d = {(1, 'a', 'a') : 2, (4, 'c', 'd'):5}
print(myFunc(d)) # True
d = {(1, 'a', 'b') : 2, (4, 'c', 'd'):5}
print(myFunc(d)) # False
Then you can customize return values how you prefer
You could pair elements for each key in the dictionary and then check if any of those pairs equals your desired result, eg:
d = {(1, 'a', 'b') : 2, (4, 'c', 'd'):5}
# Check for existence of any key matching criteria
any(pair == ('a', 'b') for key in d for pair in zip(key, key[1:]))
# True
# Filter out keys/values matching criteria
{k: v for k, v in d.items() if any(p == ('a', 'b') for p in zip(k, k[1:]))}
# {(1, 'a', 'b'): 2}
this seems to work fine
for key in d:
return key[1] == string_1 and key[2] == string_2

Creating Python defaultdict using nested list of tuples

The scenario is that I have a 2-D list. Each item of the inner list is tuple (key, value pair). The key might repeat in the list. I want to create a default-dict on the fly, in such a way that finally, the dictionary stores the key, and the cumulative sum of all the values of that key from the 2-D list.
To put the code :
listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
finalDict = defaultdict(int)
for eachItem in listOfItems:
for key, val in eachItem:
finalDict[key] += val
print(finalDict)
This is giving me what I want : defaultdict(<class 'int'>, {'a': 7, 'b': 5, 'c': 0, 'd': 5}) but I am looking for a more 'Pythonic' way using comprehensions. So I tried the below :
finalDict = defaultdict(int)
finalDict = {key : finalDict[key]+val for eachItem in listOfItems for key, val in eachItem}
print(finalDict)
But the output is : {'a': 6, 'b': 2, 'c': 0, 'd': 5} What is it that I am doing wrong? Or is it that when using comprehension the Dictionary is not created and modified on the fly?
Yes a comprehension can't be updated on-the-fly. Anyway, this task might be better suited to collections.Counter() with .update() calls:
>>> from collections import Counter
>>> c = Counter()
>>> for eachItem in listOfItems:
... c.update(dict(eachItem))
...
>>> c
Counter({'a': 7, 'b': 5, 'd': 5, 'c': 0})
This is because you do not assign any value to your finalDict inside your dict in comprehension.
In your dict in comprehension you are literally changing the type of finalDict
As far as I know you cannot assign value to your dict inside a dict in comprehension.
Here is a way to get the dictionnary you want
from functools import reduce
listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
list_dict = [{key: val} for eachItem in listOfItems for key, val in eachItem]
def sum_dict(x, y):
return {k: x.get(k, 0) + y.get(k, 0) for k in set(x) | set(y)}
print(reduce(sum_dict, list_dict))
Simple solution without using additional modules:
inp_list = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
l = [item for sublist in inp_list for item in sublist] # flatten the list
sums = [(key, sum([b for (a,b) in l if a == key])) for key in dict(l)]
print(sums)
trying to use python's built-in methods instead of coding the functionality myself:
The long and explained solution
from itertools import chain, groupby
from operator import itemgetter
listOfItems = [[('a', 1), ('b', 3)], [('a', 6)], [('c', 0), ('d', 5), ('b', 2)]]
# just flat the list of lists into 1 list..
flatten_list = chain(*listOfItems)
# get all elements grouped by the key, e.g 'a', 'b' etc..
first = itemgetter(0)
groupedByKey = groupby(sorted(flatten_list, key=first), key=first))
#sum
summed_by_key = ((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupedByKey)
# create a dict
d = dict(summed_by_key)
print(d) # {'a': 7, 'b': 5, 'c': 0, 'd': 5}
~one line solution
from itertools import chain, groupby
from operator import itemgetter
first = itemgetter(0)
d = dict((k, sum(item[1] for item in tups_to_sum)) for k, tups_to_sum in groupby(sorted(chain(*listOfItems), key=first), key=first))
print(d) # {'a': 7, 'b': 5, 'c': 0, 'd': 5}

List of tuples to nested dictionary without overriding

I need to convert the above list of tuples to nested dictionary without overwriting the value as below in python
[('a', '1'),
('b', 'true'),
('b', 'none'),
('a', '2'),
('b', 'true'),
('a', '3'),
('b', 'false')]
{'a': {'1' : { 'b' : ('true','none')},
'2' : { 'b' : ('true')},
'3' : { 'b' : ('false')}}}
Converting each tuple into dictionary using
dict()
and merging the dictionary doesn't work. Is there any pythonic way to do this?
Here's one way to do it with collections.defaultdict:
from collections import defaultdict
import pprint
data = [('a', '1'), ('b', 'true'), ('b', 'none'), ('a', '2'), ('b', 'true'), ('a', '3'), ('b', 'false')]
d = defaultdict(lambda: defaultdict(lambda: defaultdict(tuple)))
for i, j in data:
if i == 'a':
p = d[i][j]
else:
p[i] += j,
pprint.pprint(d)
# {'a': {'1': defaultdict(<class 'tuple'>, {'b': ('true', 'none')}),
# '2': defaultdict(<class 'tuple'>, {'b': ('true',)}),
# '3': defaultdict(<class 'tuple'>, {'b': ('false',)})}}
You could also use the dictionary's setdefault method to return default values for new keys, although the defaultdict approach is much cleaner and faster:
c = {}
for i, j in data:
if i == 'a':
q = c.setdefault(i, {}).setdefault(j, {})
else:
q[i] = q.setdefault(i, ()) + (j,)
pprint.pprint(c)
# {'a': {'1': {'b': ('true', 'none')},
# '2': {'b': ('true',)},
# '3': {'b': ('false',)}}}
Expanding #MosesKoledoye answer, if the first value in the dictionary is only 'a' and 'b', you know that the outer dictionary will always contain at most one element using 'a' as the key and the inner dictionary will always contain at most one element using 'b' as the key. So in the end you get the same information if it is {'1': ('true', 'none')…. You can convert that to your format simply by wrapping the data in some dictionaries. This means you can do the following
output = defaultdict(tuple)
for i, j in data:
if i == 'a':
current = j
else:
# i == 'b'
output[current] += (j, )
This will result in the following:
defaultdict(<type 'tuple'>, {'1': ('true', 'none'), '3': ('false',), '2': ('true',)})
Now to get it into a dictionary like yours you can do the following:
output = {k: {'b': v} for k, v in output.items()}
if output:
output = {'a': output}
Resulting in the following:
{'a': {'1': {'b': ('true', 'none')}, '3': {'b': ('false',)}, '2': {'b': ('true',)}}}

Python list of tuples to nested dict

I have a data structure as follows:
[(a,x1,1),(a,x2,5),(b,x1,1) ...]
and i want to turn it into a nested dictionary of the form
{a:{x1:1, x2:5}, b:{x1:1}...}
I tried
dictdata = {}
for row in rows:
ean = row[1].encode('ascii','ignore')
period = str(row[0])
value = row[2]
dictdata[ean]={} # init sub dictionary
dictdata[ean][period] = value
but every time I do dictdata[ean]={}, the contents get erased, so this will not work. If I do not initialise the sub-dictionary, I also cannot get it to work.
Any help appreciated
This is the kind of problem collections.defaultdict was built to solve:
https://docs.python.org/2/library/collections.html#collections.defaultdict
from collections import defaultdict
dictdata = defaultdict(dict)
rows = [('a','x1',1),('a','x2',5),('b','x1',1) ]
for row in rows:
ean = row[1].encode('ascii','ignore')
period = str(row[0])
value = row[2]
dictdata[period][ean] = value
dictdata
returns
{'a': {'x2': 5, 'x1': 1}, 'b': {'x1': 1}}
You can do it in one statement
rows = [('a','x1',1),('a','x2',5),('b','x1',1)]
result = dict()
for key1, key2, value in rows:
result.setdefault(key1, {}).update({key2: value})
Same thing but using defaultdict
from collections import defaultdict
rows = [("a", "x1", 1), ("a", "x2", 5), ("b", "x1", 1)]
d = defaultdict(dict)
for k, v, v2 in rows:
d[k][v] = v2
As a fix to your code, the proper way is to always if you have already the dictionary created, if not then instantiate one, like so:
>>> l
[('a', 'x1', 1), ('a', 'x2', 5), ('b', 'x1', 1)]
>>> d = {}
>>> for row in l:
ean = row[1].encode('ascii','ignore')
period = str(row[0])
value = row[2]
if period not in d:
d[period] = {}
if ean not in d[period]:
d[period][ean] = {}
d[period][ean] = value
>>> d
{'a': {b'x1': 1, b'x2': 5}, 'b': {b'x1': 1}}
You can also do it with defaultdict from collections, very straight forward:
>>> l = [('a','x1',1),('a','x2',5),('b','x1',1)]
>>>
>>> from collections import defaultdict
>>>
>>>
>>> d = defaultdict(dict)
>>>
>>> for k, k_sub, v in l:
d[k][k_sub] = v
>>> d
defaultdict(<class 'dict'>, {'a': {'x1': 1, 'x2': 5}, 'b': {'x1': 1}})
Solution for an arbitrary length of tuples:
l = [('a', 'x1', 1), ('a', 'x2', 5), ('b', 'x1', 1), ('a', 'x3', 'y1', 'z1', 7), ('a', 'x3', 'y1', 'z2', 666)]
def f(data):
def _f(store, keys, value):
if len(keys) == 1:
return {keys[0]: value}
store[keys[0]].update(_f(defaultdict(dict), keys[1:], value))
return store
result = defaultdict(dict)
for a in data:
_f(result, a[:-1], a[-1])
return dict(result)
print(f(l))
{'a': {'x1': 1, 'x2': 5, 'x3': {'y1': {'z2': 666}}}, 'b': {'x1': 1}}

Categories

Resources