Dynamically join of dictionary - python

a="90342"
# this used to generate a dict of each char in a and it indexs
modchar=[{i:a.index(i)} for i in a ]
#modchar=[{'9': 0}, {'0': 1}, {'3': 2}, {'4': 3}, {'2': 4}]
# below produce combination now this combination
def combination(x,n):
return list(itertools.combinations(x,n))
combination(modchar,1)
#output [({'9': 0},), ({'0': 1},), ({'3': 2},), ({'4': 3},), ({'2': 4},)]
combination(modchar,2)
#output [({'9': 0}, {'0': 1}), ({'9': 0}, {'3': 2}), ({'9': 0}, {'4': 3}), ({'9': 0}, {'2': 4}), ({'0': 1}, {'3': 2}), ({'0': 1}, {'4': 3}), ({'0': 1}, {'2': 4}), ({'3': 2}, {'4': 3}), ({'3': 2}, {'2': 4}), ({'4': 3}, {'2': 4})]
combination(modchar,3)
#output [({'9': 0}, {'0': 1}, {'3': 2}), ({'9': 0}, {'0': 1}, {'4': 3}), ({'9': 0}, {'0': 1}, {'2': 4}), ({'9': 0}, {'3': 2}, {'4': 3}),....]
if u look at each result in the list first element is tuple of dict.what i want to do is to combine the dictionary inside the tuple and make it as single dict
i have tried
map(lambda x:dict(x[0],**x[1]),list(itertools.combinations(x,n)))
above works only for tuple of two dicts.
how can i produce a code dynamically it should combine all dicts and produce single dict irrespictive of n value in combination(x,n)
expected output: for n=2
[({'9': 0,'0': 1}) ....]
expected output: for n=3
[({'9': 0,'0': 1,'3': 2})..]

Here's a way to do it:
combos = combinations(modchar,3)
def combineDictTuple(dt):
d = {}
for item in dt:
d.update(item)
return d
newCombos = [combineDictTuple(dt) for dt in combos]
# OUTPUT: [{'9': 0, '0': 1, '3': 2}, {'9': 0, '0': 1, '4': 3}, {'9': 0, '0': 1, '2': 4}, {'9': 0, '3': 2, '4': 3}, {'9': 0, '3': 2, '2': 4}, {'9': 0, '2': 4, '4': 3}, {'0': 1, '3': 2, '4': 3}, {'0': 1, '3': 2, '2': 4}, {'0': 1, '2': 4, '4': 3}, {'3': 2, '2': 4, '4': 3}]

This should do what you want:
>>> def update_with_return(d1, d2):
... d1.update(d2)
... return d1
...
>>> reduce(update_with_return, ({'a': 1}, {'b':2}), dict())
{'a': 1, 'b': 2}

Related

How to split python list into segments based on elements' attributes?

I have a list like:
[
{'p': 0},
{'p': 1},
{'p': 1},
{'p': 0},
{'p': 0},
{'p': 2}
]
I want to split it into segments based on attribute p, so the result would be:
[[{'p':0}], [{'p':1}, {'p':1}], [{'p':0}, {'p':0}], [{'p':2}]]
As mentioned you can use itertools:
import itertools
list_p = [
{'p': 0},
{'p': 1},
{'p': 1},
{'p': 0},
{'p': 0},
{'p': 2}
]
list_p_groups = []
for key, group in itertools.groupby(list_p):
list_p_groups.append(list(group))
for item in list_p_groups:
print(item)
Outputs:
[{'p': 0}]
[{'p': 1}, {'p': 1}]
[{'p': 0}, {'p': 0}]
[{'p': 2}]

Find common elements and their frequency in list of dictionaries

I have multiple (~40) lists that contain dictionaries, that I would like to find
which are those list items (in this case dictionaries) that are common in all lists
how many times each unique item appears across all lists.
Some examples of the lists are:
a = [{'A': 0, 'B': 0},
{'A': 0, 'C': 1},
{'D': 1, 'C': 0},
{'D': 1, 'E': 0}]
b = [{'A': 0},
{'B': 0, 'C': 1},
{'D': 1, 'C': 0},
{'D': 1, 'E': 0}]
c = [{'C': 0},
{'B': 1},
{'D': 1, 'C': 0, 'E': 0},
{'D': 1, 'E': 0}]
What I tried so far, it is the following code, but it returned values that were not common in all lists...
def flatten(map_groups):
items = []
for group in map_groups:
items.extend(group)
return items
def intersection(map_groups):
unique = []
items = flatten(map_groups)
for item in items:
if item not in unique and items.count(item) > 1:
unique.append(item)
return unique
all_lists = [a,b,c]
intersection(all_lists)
What I would expect to get as a result would be:
1. {'D': 1, 'E': 0} as a common item in all lists
2. {'D': 1, 'E': 0}, 3
{'D': 1, 'C': 0}, 2
{'A': 0, 'B': 0}, 1
{'A': 0, 'C': 1}, 1
{'A': 0}, 1
{'B': 0, 'C': 1}, 1
{'C': 0},
{'B': 1},
{'D': 1, 'C': 0, 'E': 0}
To count things, python comes with a nice class: collections.Counter. Now the question is: What do you want to count?
For example, if you want to count the dictionaries that have the same keys and values, you can do something like this:
>>> count = Counter(tuple(sorted(x.items())) for x in a+b+c)
>>> count.most_common(3)
[((('C', 0), ('D', 1)), 2), ((('D', 1), ('E', 0)), 2), ((('A', 0), ('B', 0)), 1)]
The dictionaries here are converted to tuples with sorted items to make them comparable and hashable. Getting for example the 3 most common back as a list of dictionaries is also not too hard:
>>> [dict(x[0]) for x in count.most_common(3)]
[{'C': 0, 'D': 1}, {'D': 1, 'E': 0}, {'A': 0, 'B': 0}]
You can use a nested for loop:
a = [{'A': 0, 'B': 0},
{'A': 0, 'C': 1},
{'D': 1, 'C': 0},
{'D': 1, 'E': 1}]
b = [{'A': 0},
{'B': 0, 'C': 1},
{'D': 1, 'C': 0},
{'D': 1, 'E': 0}]
c = [{'C': 0},
{'B': 1},
{'D': 1, 'C': 0, 'E': 0},
{'D': 1, 'E': 0}]
abc_list = [*a, *b, *c]
abc = list()
for d in abc_list:
for i in abc:
if d == i[0]:
abc[abc.index(i)] = (d, i[1] + 1)
continue
abc.append((d, 1))
print(abc)
Output:
[({'A': 0, 'B': 0}, 1),
({'A': 0, 'C': 1}, 1),
({'D': 1, 'C': 0}, 2),
({'D': 1, 'E': 1}, 1),
({'A': 0}, 1),
({'B': 0, 'C': 1}, 1),
({'D': 1, 'E': 0}, 2),
({'C': 0}, 1),
({'B': 1}, 1),
({'D': 1, 'C': 0, 'E': 0}, 1)]
Explanation:
The line
[*a, *b, *c]
unpacks all the values in lists a, b and c into a single list, which \i named abc_list.
The continue statement where I put it means to directly continue to the next iteration of the inner for loop, without reaching abc.append((d, 1)).
The above output answers question 2. For question 1, we can use the built-in max() method on the abc list, with a custom key:
print(max(ABC, key=lambda x:x[1])[0])
Of course, it will only return one dictionary, {'D': 1, 'C': 0}. If you want to print out multiple dictionaries that appear the most frequently:
m = max(abc, key=lambda x:x[1])[1]
for d in abc:
if d[1] == m:
print(d[0])
Output:
{'D': 1, 'C': 0}
{'D': 1, 'E': 0}

In python: filter out elements in a list of dicts where some property is underrepresented

I have a list of dictionaries
[ {'x': 1, 'cat': 1},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 3}]
I need to filter out elements who's 'cat' value is present too few times
if I set the minimum number of instances to two, in the list above, the instance containing 'cat': 3 should be filtered out because 'cat':3 is present only once in the list, there are enough instances of 'cat': 1 and 'cat': 2
the output should be
[ {'x': 1, 'cat': 1},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2}]
I don't care about the order, I need to keep original dictionaries
You could use collections.Counter to check the frequency of categories and build a set from the ones that are frequent enough:
import collections
source = [{'x': 1, 'cat': 1},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 3}]
minimum_count = 2
category_counts = collections.Counter(item['cat'] for item in source)
# category_counts == {1: 4, 2: 3, 3: 1}
frequent_categories = {
category for category, count in category_counts.items()
if count > minimum_count
}
# frequent_categories == {1, 2}
result = [item for item in source if item['cat'] in frequent_categories]
you can try this code:
l = [
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 1},
{'x': 1, 'cat': 2},
{'x': 1, 'cat': 3}
]
from collections import Counter
def select(l, times):
counters = Counter(map(lambda x : x['cat'], l)).most_common(times)
return filter(lambda item: item['cat'] in dict(counters) , l)
print select(l, 2)

Updating the dictionary in the for loop

I have such code, dictionary x must be created outside the loop for:
one = [1,3,3,4,5,6]
x = {'x': {}, 'a': 1}
t = []
for i in one:
x['x'] = {'z': i}
t.append(x)
Why i`m getting this:
[{'a': 1, 'x': {'z': 6}}, {'a': 1, 'x': {'z': 6}}, {'a': 1, 'x': {'z': 6}}, {'a': 1, 'x': {'z': 6}}, {'a': 1, 'x': {'z': 6}}, {'a': 1, 'x': {'z': 6}}]
I hope to have this:
[{'a': 1, 'x': {'z': 1}}, {'a': 1, 'x': {'z': 3}}, {'a': 1, 'x': {'z': 3}}, {'a': 1, 'x': {'z': 4}}, {'a': 1, 'x': {'z': 5}}, {'a': 1, 'x': {'z': 6}}]
Because you are actually modifying the same x object in your loop, so they all point to the same object. That is why all values of z in the dictionary have the last value.
You could use the following list comprehension
t = [{'x': {'z': i}, 'a':1} for i in one]
Output
>>> t
[{'x': {'z': 1}, 'a': 1},
{'x': {'z': 3}, 'a': 1},
{'x': {'z': 3}, 'a': 1},
{'x': {'z': 4}, 'a': 1},
{'x': {'z': 5}, 'a': 1},
{'x': {'z': 6}, 'a': 1}]
You've got a single x object you're modifying and re-appending to t. In other words, this line: x['x'] = {'z': i} does not create a new object, it modifies it. After the loop the list is holding six references to the same single object.
one = [1,3,3,4,5,6]
t = []
for i in one:
t.append({'x': {'z': i}, 'a': 1}) # new/dict object each iteration
print(t)
[{'a': 1, 'x': {'z': 1}}, {'a': 1, 'x': {'z': 3}}, {'a': 1, 'x': {'z': 3}}, {'a': 1, 'x': {'z': 4}}, {'a': 1, 'x': {'z': 5}}, {'a': 1, 'x': {'z': 6}}]

Finding Index in string with recurring chars

I have string a='51545'
I am finding index of the each char in the string like this
modchar=[{i:a.index(i)} for i in a ]
#modchar=[{'5': 0}, {'1': 1}, {'5': 0}, {'4': 3}, {'5': 0}]
but i need to get it as
#modchar=[{'5': 0}, {'1': 1}, {'5': 2}, {'4': 3}, {'5': 4}]
How can we achieve this?
In this case, you probably want to enumerate the string creating the dictionaries as you go:
[{c: i} for i, c in enumerate(a)]
Note that as a side bonus, this happens in O(n) time opposed to your original solution which is O(n^2)
Try this:
a='51545'
obj = []
for i in range(len(a)):
obj.append({a[i]: i})
This runs as:
>>> a='51545'
>>> obj = []
>>> for i in range(len(a)):
... obj.append({a[i]: i})
...
>>> obj
[{'5': 0}, {'1': 1}, {'5': 2}, {'4': 3}, {'5': 4}]
>>>
You can do list comprehension using enumerate:
[{value: index} for value, index in enumerate(a)]
Which runs as:
>>> [{value: index} for index, value in enumerate(a)]
[{'5': 0}, {'1': 1}, {'5': 2}, {'4': 3}, {'5': 4}]
>>>
Or, you can use a basic list comprehension:
[{a[index]: index} for index in range(len(a))]
Which runs as:
>>> [{a[index]: index} for index in range(len(a))]
[{'5': 0}, {'1': 1}, {'5': 2}, {'4': 3}, {'5': 4}]
>>>
enumerate is basically a combination of using a for loop to get the index, and then accessing the list:
>>> arr = [5, 8, 2, 4]
>>> for index, value in enumerate(arr):
... print index, value
...
0 5
1 8
2 2
3 4
>>>

Categories