how to convert a list to a default dictionary - python

I want to convert a list to a default dictionary to have a default value of 0 in case the key doesn't have any value (from the list).
list : order = ['a',1,'b',2,'c']
what I did using ZIP :
it = iter(order)
res_dict = dict(zip(it,it))
print(res_dict)
but it excludes c as a key, as the list doesn't have the next index after c.
Result I got : {'a': 1, 'b': 2}
Result i want : {'a': 1, 'b': 2, 'c': 0}

You might want to consider using itertools and .zip_longest().
For example:
import itertools
l = ['a',1,'b',2,'c']
d = dict(itertools.zip_longest(l[::2], l[1::2], fillvalue=0))
print(d)
Output:
{'a': 1, 'b': 2, 'c': 0}

This is working:
d = dict()
for i in range(len(order)):
if i%2==0 and i+1<len(order):
d[order[i]] =order[i+1]
elif i+2>(len(order)):
d[order[i]]=0
Result:
{'a': 1, 'b': 2, 'c': 0}

To solve the problem of two consequent keys you can use a custom function to split the list
def splitdefault(o):
i = 0
while i < len(o):
# there is a next element to check
if i + 1 < len(o):
# the next element is int
if isinstance(o[i + 1], int):
yield o[i], o[i + 1]
i += 2
else:
yield o[i], 0
i += 1
# i is the last element
else:
yield o[i], 0
i += 1
order = ["a", 1, "b", 2, "c", "d", 3, "e"]
for g in splitdefault(order):
print(g)
res_dict = dict(splitdefault(order))
print(res_dict)
Which produces
{'a': 1, 'b': 2, 'c': 0, 'd': 3, 'e': 0}
Cheers!

Related

Merging two lists with different lengths in python and counting elements

I have a list as follows:
[[a,a,b,a,b,b,b],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
The number of lists containing numerical values is the same as the elements in the first list (that contains letters "a" or "b"). The length of the lists containing numbers is unknown a priori.
Each letter corresponds to a list in this way:
a --> 5,5,4,5
a --> 5,1,5
b --> 2,5
a --> 4,5
b --> 5
b --> 3
b --> 5
And then, count each value by letters "a" or "b", while keeping the values, for example "a" has in total 6 "5", 2 "4", and 1 "1". "b" has in total 3 "5", 1 "2", and 1 "3".
Expected result:
"a" has in total 6 "5", 2 "4", and 1 "1".
"b" has in total 3 "5", 1 "2", and 1 "3".
One approach:
from collections import Counter, defaultdict
lst = [["a", "a", "b", "a", "b", "b", "b"], [5, 5, 4, 5], [5, 1, 5], [2, 5], [4, 5], [5], [3], [5]]
result = defaultdict(Counter)
head, *tail = lst
for key, values in zip(head, tail):
result[key] += Counter(values)
for key, counts in result.items():
print(key, counts)
Output
a Counter({5: 6, 4: 2, 1: 1})
b Counter({5: 3, 2: 1, 3: 1})
An alternative:
head, *tail = lst
counts = Counter((key, value) for key, values in zip(head, tail) for value in values)
result = defaultdict(dict)
for (key, value), count in counts.items():
result[key][value] = count
for key, value in result.items():
print(key, value)
Output
a {5: 6, 4: 2, 1: 1}
b {2: 1, 5: 3, 3: 1}
This would be my approach:
inputs = [['a','a','b','a','b','b','b'],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
counts = {}
for k, v in zip(inputs[0], inputs[1:]):
if k in counts.keys():
counts[k] += v
else:
counts[k] = v
My output for this:
{'a': [5, 5, 4, 5, 5, 1, 5, 4, 5], 'b': [2, 5, 5, 3, 5]}
Then you can use Counters, len(), etc. to get the exact output formatting you want.
See below ( Counter and defaultdict are the main "players")
from collections import Counter,defaultdict
results = defaultdict(Counter)
data = [['a','a','b','a','b','b','b'],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
for idx,x in enumerate(data[0],1):
results[x].update(data[idx])
for letter,counter in results.items():
print(f'{letter} -> {counter}')
output
a -> Counter({5: 6, 4: 2, 1: 1})
b -> Counter({5: 3, 2: 1, 3: 1})
It's a fun problem to solve.
from collections import Counter
data = [['a','a','b','a','b','b','b'],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
counts = { k:Counter() for k in list(set(data[0])) }
for i, k in enumerate(data[0], 1):
counts[k].update(data[i])
print(counts)
# {'a': Counter({5: 6, 4: 2, 1: 1}), 'b': Counter({5: 3, 2: 1, 3: 1})}
l = [["a","a","b","a","b","b","b"],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
d = {}
for i in l[0]:
if i not in d.keys():
d[i] = []
for i, item in zip(l[0],l[1:]):
d[i].append(item)
count_dict = {}
for i in d.keys():
count_dict[i] = {}
for j in d[i]:
elements = set(j)
for k in elements:
if str(k) not in count_dict[i].keys():
count_dict[i][str(k)] = j.count(k)
else:
count_dict[i][str(k)] += j.count(k)
for i,j in count_dict.items():
print('{} has {}'.format(i,j))
First off, you should really be doing your own homework
... I just love a good algo problem (adventOfCode, anyone?)
Steps:
don't forget " around strings in the list
create a dictionary to store counts within "a" and "b"
iterate over lists in indices 1-n
get the a/b bucket from: l[0][sublist_index - 1]
start a count for value, if not already counted: if v not in d[bucket].keys(): d[bucket][v] = 0
increment the counter for v, in the appropriate bucket: d[bucket][v] += 1
l = [["a","a","b","a","b","b","b"],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
d = {"a": {}, "b": {}}
for sublist_index in range(1, len(l)):
bucket = l[0][sublist_index - 1]
for v in l[sublist_index]:
if v not in d[bucket].keys():
d[bucket][v] = 0
d[bucket][v] += 1
print(d)
and the output:
{'a': {5: 6, 4: 2, 1: 1}, 'b': {2: 1, 5: 3, 3: 1}}

Nesting dictionary algorithm

Suppose I have the following dictionary:
{'a': 0, 'b': 1, 'c': 2, 'c.1': 3, 'd': 4, 'd.1': 5, 'd.1.2': 6}
I wish to write an algorithm which outputs the following:
{
"a": 0,
"b": 1,
"c": {
"c": 2,
"c.1": 3
},
"d":{
"d": 4,
"d.1": {
"d.1": 5,
"d.1.2": 6
}
}
}
Note how the names are repeated inside the dictionary. And some have variable level of nesting (eg. "d").
I was wondering how you would go about doing this, or if there is a python library for this? I know you'd have to use recursion for something like this, but my recursion skills are quite poor. Any thoughts would be highly appreciated.
You can use a recursive function for this or just a loop. The tricky part is wrapping existing values into dictionaries if further child nodes have to be added below them.
def nested(d):
res = {}
for key, val in d.items():
t = res
# descend deeper into the nested dict
for x in [key[:i] for i, c in enumerate(key) if c == "."]:
if x in t and not isinstance(t[x], dict):
# wrap leaf value into another dict
t[x] = {x: t[x]}
t = t.setdefault(x, {})
# add actual key to nested dict
if key in t:
# already exists, go one level deeper
t[key][key] = val
else:
t[key] = val
return res
Your example:
d = {'a': 0, 'b': 1, 'c': 2, 'c.1': 3, 'd': 4, 'd.1': 5, 'd.1.2': 6}
print(nested(d))
# {'a': 0,
# 'b': 1,
# 'c': {'c': 2, 'c.1': 3},
# 'd': {'d': 4, 'd.1': {'d.1': 5, 'd.1.2': 6}}}
Nesting dictionary algorithm ...
how you would go about doing this,
sort the dictionary items
group the result by index 0 of the keys (first item in the tuples)
iterate over the groups
if there are is than one item in a group make a key for the group and add the group items as the values.
Slightly shorter recursion approach with collections.defaultdict:
from collections import defaultdict
data = {'a': 0, 'b': 1, 'c': 2, 'c.1': 3, 'd': 4, 'd.1': 5, 'd.1.2': 6}
def group(d, p = []):
_d, r = defaultdict(list), {}
for n, [a, *b], c in d:
_d[a].append((n, b, c))
for a, b in _d.items():
if (k:=[i for i in b if i[1]]):
r['.'.join(p+[a])] = {**{i[0]:i[-1] for i in b if not i[1]}, **group(k, p+[a])}
else:
r[b[0][0]] = b[0][-1]
return r
print(group([(a, a.split('.'), b) for a, b in data.items()]))
Output:
{'a': 0, 'b': 1, 'c': {'c': 2, 'c.1': 3}, 'd': {'d': 4, 'd.1': {'d.1': 5, 'd.1.2': 6}}}

Iterate over X dictionary items in Python

How can I iterate over only X number of dictionary items? I can do it using the following bulky way, but I am sure Python allows a more elegant way.
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
x = 0
for key in d:
if x == 3:
break
print key
x += 1
If you want a random sample of X values from a dictionary you can use random.sample on the dictionary's keys:
from random import sample
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
X = 3
for key in sample(d, X):
print key, d[key]
And get output for example:
e 5
c 3
b 2

Python set an item value based other items in a dictionary

A = {0:{a:1, b:7}, 1:{a:5,b:5}, 2:{a:4,b:6}}
I want to attach an item guess to each sub dictionary based on the value b accounting of all b's in each sub dictionary.
Saying, in Dictionary A:
0-b-7 percentage of b: 7/(7+5+6)
1-b-5 percentage of b: 5/(7+5+6)
2-b-6 percentage of b: 1 - 7/(7+5+6) - 5/(7+5+6)
The desired Dictionary should be like
A = {0:{a:1, b:7, 'guess': 7/(7+5+6)},
1:{a:5,b:5, 'guess': 5/(7+5+6)},
2:{a:4,b:6, 'guess': 1 - 7/(7+5+6) - 5/(7+5+6)}}
I don't know how to incorporate the other two b's for a specific subdictionary.
One approach is to precompute the sum of all bs and then use it to add a new key-value pair to your dictionary.
b_total = float(sum(A[k]['b'] for k in A))
for k in A:
A[k]['guess'] = A[k]['b'] / b_total
#{0: {'a': 1, 'b': 7, 'guess': 0.3888888888888889},
# 1: {'a': 5, 'b': 5, 'guess': 0.2777777777777778},
# 2: {'a': 4, 'b': 6, 'guess': 0.3333333333333333}}
A = {0:{"a":1, "b":7}, 1:{"a":5,"b":5}, 2:{"a":4,"b":6}}
char = "b"
denominator = 0
# =========================
# First Calculate the sum
# =========================
for key in A:
inner_map = A[key]
denominator += inner_map[char]
# ========================================
# Now insert the new key to the inner_map
# ========================================
for key in A:
inner_map = A[key]
inner_map["guess"] = inner_map[char]/denominator
print(A)
Output:
{0: {'a': 1, 'b': 7, 'guess': 0.3888888888888889}, 1: {'a': 5, 'b': 5, 'guess': 0.2777777777777778}, 2: {'a': 4, 'b': 6, 'guess': 0.3333333333333333}}
Try this:
def add_calc(my_dict):
total_guesses = sum(map(lambda x: my_dict.get(x).get('b'), my_dict))
for item in my_dict.itervalues():
item.update({'guess': 1.0 * item.get('b') / total_guesses})
return my_dict
d = add_calc(A)
{0: {'a': 1, 'b': 7, 'guess': 0.3888888888888889},
1: {'a': 5, 'b': 5, 'guess': 0.2777777777777778},
2: {'a': 4, 'b': 6, 'guess': 0.3333333333333333}}
I'm on Python 2 btw, you didn't specify version
You can use dictionary unpacking:
A = {0:{'a':1, 'b':7}, 1:{'a':5, 'b':5}, 2:{'a':4, 'b':6}}
results = {a:{**b, **{'guess':b['b']/float(sum(c['b'] for _, c in A.items()))}} for a, b in A.items()}
Output:
{0: {'guess': 0.3888888888888889, 'b': 7, 'a': 1}, 1: {'guess': 0.2777777777777778, 'b': 5, 'a': 5}, 2: {'guess': 0.3333333333333333, 'b': 6, 'a': 4}}

Python: summarizing data from list using index from another list

I have two lists:
L1 = ['A','B','A','C','A']
L2 = [1, 4, 6, 1, 3]
I want to create a dictionary which has the following output:
DictOutSum = {'A':10, 'B':4, 'C':1}
DictOutCount = {'A':3, 'B':1, 'C':1}
i.e. Lists L1 and L2 both have same number of elements and the elements in them corresponds one to one. I want to find sum of all numbers in L2 for each unique element in L1 and make a dictionary out of it(DictOutSum). I also want to create another dictionary which stores the counts of number of unique elements of L1(DictOutCount).
I don't even have an idea where to start for this other than to use a for loop.
Pure python implementation:
>>> dict_sum = dict.fromkeys(L1, 0)
>>> dict_count = dict.fromkeys(L1, 0)
>>> for k,n in zip(L1, L2):
... dict_sum[k] += n
... dict_count[k] += 1
...
>>> dict_sum
{'A': 10, 'B': 4, 'C': 1}
>>> dict_count
{'A': 3, 'B': 1, 'C': 1}
Fancy one-liner implementations:
>>> from collections import Counter
>>> Counter(L1) # dict_count
Counter({'A': 3, 'B': 1, 'C': 1})
>>> sum((Counter({k:v}) for k,v in zip(L1, L2)), Counter()) # dict_sum
Counter({'A': 10, 'B': 4, 'C': 1})
You should use the zip builtin function
import collections
DictOutSum = collections.defaultdict(int)
DictOutCount = collections.defaultdict(int)
for l1, l2 in zip(L1, L2):
DictOutSum[l1] += l2
DictOutCount[l1] += 1
>>> L1 = ['A','B','A','C','A']
>>> L2 = [1, 4, 6, 1, 3]
>>>
>>> DictOutCount = {v:0 for v in L1}
>>> DictOutSum = {v:0 for v in L1}
>>> for v1,v2 in zip(L1,L2):
... DictOutCount[v1] += 1
... DictOutSum[v1] += v2
...
>>>
>>> DictOutCount
{'A': 3, 'C': 1, 'B': 1}
>>> DictOutSum
{'A': 10, 'C': 1, 'B': 4}
>>>
The mega elementary way
L1 = ['A','B','A','C','A']
L2 = [1, 4, 6, 1, 3]
# Carries the information
myDict = {}
# Build the dictionary
for x in range(0,len(L1)):
# Initialize the dictionary IF the key doesn't exist
if L1[x] not in myDict:
myDict[L1[x]] = {}
myDict[L1[x]]['sum'] = 0
myDict[L1[x]]['count'] = 0
# Collect the information you need
myDict[L1[x]][x] = L2[x]
myDict[L1[x]]['sum'] += L2[x]
myDict[L1[x]]['count'] += 1
# Build the other two dictionaries
DictOutSum = {}
DictOutCount = {}
# Literally feed the data
for element in myDict:
DictOutSum[element] = myDict[element]['sum']
DictOutCount[element] = myDict[element]['count']
print DictOutSum
# {'A': 10, 'C': 1, 'B': 4}
print DictOutCount
# {'A': 3, 'C': 1, 'B': 1}
Side note: From your username, are you Persian?
DictOutCount, use collections.Counter,
import collections
DictOutCount = collections.Counter(L1)
print(DictOutCount)
Counter({'A': 3, 'C': 1, 'B': 1})
DictOutSum,
DictOutSum = dict()
for k, v in zip(L1, L2):
DictOutSum[k] = DictOutSum.get(k, 0) + v
print(DictOutSum)
# Output
{'A': 10, 'C': 1, 'B': 4}
Previous answer, DictOutSum,
import itertools
import operator
import functools
DictOutSum = dict()
for name, group in itertools.groupby(sorted(itertools.izip(L1, L2)), operator.itemgetter(0)):
DictOutSum[name] = functools.reduce(operator.add, map(operator.itemgetter(1), group))
print(DictOutSum)
{'A': 10, 'C': 1, 'B': 4}
The main steps are:
use itertools.izip to make an iterator that aggregates elements from each of L1 and L2
use itertools.groupby to make an iterator that returns consecutive keys and groups from the iterable (sorting before that)
use functools.reduce for cumulatively addition

Categories