Combinations of elements to form nested dictionary - python

I have a dictionary, with integers as key (1 up to n), and values being lists (1 up to m elements). I would like to create a new dictionary, with the primary key being an integer (1 up to each n * m), and the secondary key the original n key with values as strings from the list.
Input:
input = {
1: ['foo', ...],
2: ['buz', ...],
3: ['sam', 'foo', ...],
4: ['bar', ...],
5: ['foo', 'bar', ...]
...
}
Where ... marks more values being present. Values are sometimes the same, sometimes not, and order is not important here even though I used lists.
Output: for this particular case (if ... omitted).
output = {
1: {1: 'foo', 2: 'buz', 3: 'sam', 4: 'bar', 5: 'foo'},
2: {1: 'foo', 2: 'buz', 3: 'sam', 4: 'bar', 5: 'bar'},
3: {1: 'foo', 2: 'buz', 3: 'bar', 4: 'bar', 5: 'foo'},
4: {1: 'foo', 2: 'buz', 3: 'bar', 4: 'bar', 5: 'bar'}
}
Edit: second example
input = {
1: ['alice'],
2: ['tom', 'josh'],
3: ['mike', 'adam'],
4: ['kate', 'filip'],
}
output = {
1: {1: 'alice', 2: 'tom', 3: 'mike', 4: 'kate'},
2: {1: 'alice', 2: 'tom', 3: 'mike', 4: 'filip'},
3: {1: 'alice', 2: 'tom', 3: 'adam', 4: 'kate'},
4: {1: 'alice', 2: 'tom', 3: 'adam', 4: 'filip'},
5: {1: 'alice', 2: 'josh', 3: 'mike', 4: 'kate'},
6: {1: 'alice', 2: 'josh', 3: 'mike', 4: 'filip'},
7: {1: 'alice', 2: 'josh', 3: 'adam', 4: 'kate'},
8: {1: 'alice', 2: 'josh', 3: 'adam', 4: 'filip'},
}
If someone has at least a hint I would very much appreciate it. Since I can't find the working solution at all.
Thanks all in advance

You can use itertools.product and a nested dictionary comprehension:
from itertools import product
out = {i+1: {j+1: e for j,e in enumerate(x)}
for i,x in enumerate(product(*data.values()))}
output:
{1: {1: 'foo', 2: 'buz', 3: 'sam', 4: 'bar', 5: 'foo'},
2: {1: 'foo', 2: 'buz', 3: 'sam', 4: 'bar', 5: 'bar'},
3: {1: 'foo', 2: 'buz', 3: 'foo', 4: 'bar', 5: 'foo'},
4: {1: 'foo', 2: 'buz', 3: 'foo', 4: 'bar', 5: 'bar'}}
Input:
data = {1: ['foo'], 2: ['buz'], 3: ['sam', 'foo'], 4: ['bar'], 5: ['foo', 'bar']}

Related

how can I add an element to a nested dictionary [duplicate]

This question already has answers here:
How do I initialize a dictionary of empty lists in Python?
(7 answers)
Closed last month.
here's my code:
import copy
teamdict = {1:{},2:{},3:{},4:{},5:{}}
teamlst = []
matchlst = [1,2,3,4,5]
lst = [[1,5,0],[1,0,3],[2,3,0],[2,0,1],[3,0,6],[3,0,1],[4,0,1],[4,0,5],[5,0,8]]
for i in matchlst:
for j in lst:
if i == j[0]:
teamlst.append(j[2])
elif len(teamlst)>0 and i != j:
continue
else:
pass
teamlst = set(teamlst)
teamlst = list(teamlst)
teamlst.sort()
team_dictionary = dict.fromkeys(teamlst, [])
teamdict[i] = team_dictionary
teamlst.clear()
print(teamdict)
dic = copy.deepcopy(teamdict)
for i in lst:
dic[i[0]][i[2]].append(i[1])
print(dic)
this is what i got:
{1: {0: [5, 0], 3: [5, 0]}, 2: {0: [3, 0], 1: [3, 0]}, 3: {1: [0, 0], 6: [0, 0]}, 4: {1: [0, 0], 5: [0, 0]}, 5: {8: [0]}}
but what i expect is:
{1: {0: [5], 3: [0]}, 2: {0: [3], 1: [0]}, 3: {1: [0], 6: [0]}, 4: {1: [0], 5: [0]}, 5: {8: [0]}}
what goes wrong?
seems like this append method add the element to all the keys in the nested dictionary
I assume you have created your dictionary with multiple references to the same list.
If I execute your code I get what you want.
>>> lst = [[1,5,0],[1,0,3],[2,3,0],[2,0,1],[3,0,6],[3,0,1],[4,0,1],[4,0,5],[5,0,8]]
>>> dic = {1: {0: [], 3: []}, 2: {0: [], 1: []}, 3: {1: [], 6: []}, 4: {1: [], 5: []}, 5: {8: []}}
>>> for i in lst:
... dic[i[0]][i[2]].append(i[1])
...
>>> print(dic)
{1: {0: [5], 3: [0]}, 2: {0: [3], 1: [0]}, 3: {1: [0], 6: [0]}, 4: {1: [0], 5: [0]}, 5: {8: [0]}}

Combine two dictionaries based on value of 1st and key of 2nd

I have the following two dictionaries:
{1: ['1'], 2: ['1'], 3: ['1'], 4: ['2'], 5: ['1']}
{1: ['2|N|'], 2: ['1|N|']}
I want to take the key of dictionary 2 and link it with the value's of dictionary 1, for a desired output of the following:
{1: ['2|N|'], 2: ['2|N|'], 3: ['2|N|'], 4: ['1|N|'], 5: ['2|N|']}
Basically combining the key, value of dictionary 2 on the value of dictionary 1.
Pretty straightforward solution:
adict = {1: ['1'], 2: ['1'], 3: ['1'], 4: ['2'], 5: ['1']}
mapping = {1: ['2|N|'], 2: ['1|N|']}
for key, value in adict.items():
adict[key] = [mapping[int(k)][0] for k in value]
print(adict)
Output:
{1: ['2|N|'], 2: ['2|N|'], 3: ['2|N|'], 4: ['1|N|'], 5: ['2|N|']}
here is dict comprehension manner of it
{k:b[int(v[0])] for k,v in a.items() }
{1: ['2|N|'], 2: ['2|N|'], 3: ['2|N|'], 4: ['1|N|'], 5: ['2|N|']}

Fixing column names and renaming them after grouping the dataframe by two columns

I have a dataframe:
{'ARTICLE_ID': {0: 111, 1: 111, 2: 222, 3: 222, 4: 222}, 'CITEDIN_ARTICLE_ID': {0: 11, 1: 11, 2: 11, 3: 22, 4: 22}, 'enrollment': {0: 10, 1: 10, 2: 10, 3: 10, 4: 10}, 'Trial_year': {0: 2017, 1: 2017, 2: 2017, 3: 2017, 4: 2017}, 'AUTHOR_ID': {0: 'aaa', 1: 'aaa', 2: 'aaa', 3: 'aaa', 4: 'aaa'}, 'AUTHOR_RANK': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5}}
I am grouping it by two columns
df_grouped = df.groupby(['AUTHOR_ID', 'Trial_year']).agg({'ARTICLE_ID': "count",
'enrollment': ["count", 'sum']}).reset_index()
As a result, I receive this dataframe, where column names have two levels
{('AUTHOR_ID', ''): {0: 'aaa'}, ('Trial_year', ''): {0: 2017}, ('ARTICLE_ID', 'count'): {0: 5}, ('enrollment', 'count'): {0: 5}, ('enrollment', 'sum'): {0: 50}}
My ideal output - the dataframe with one level of column names and renamed column names
`AUTHOR_ID`, `Trial_year`, `ARTICLE_ID_count`, `enrollment_count`, `enrollment_sum`
You can modify the columns:
df_grouped.columns = [f"{i}_{j}" if j!='' else i for i,j in df_grouped.columns]
or use NamedAgg from the beginning:
df_grouped = (df.groupby(['AUTHOR_ID', 'Trial_year'])
.agg(ARTICLE_ID_count=('ARTICLE_ID', "count"),
enrollment_count=('enrollment','count'),
enrollment_sum=('enrollment','sum')).reset_index())
You can also pass a dictionary to groupby.agg for a little concise code:
df_grouped = (df.groupby(['AUTHOR_ID', 'Trial_year'], as_index=False)
.agg(**{'_'.join(pair): pair for pair in [('ARTICLE_ID', 'count'),
('enrollment','count'),
('enrollment','sum')]}))
Output:
AUTHOR_ID Trial_year ARTICLE_ID_count enrollment_count enrollment_sum
0 aaa 2017 5 5 50

Creating a nested dictionary with a for loop in Python

I am trying to get the Expected Output below where it makes subfolders named John1, John2, John3 below and then it adds {0: 'John', 1: 'John', 2: 'John', 3: 'John'} values to each essentially creating a nested dictionary. How would I be able to do that and get the Expected Output?
dicts = {}
keys = range(4)
name_vals = ['John'+str(k+1) for k in range(3)]
values = ["Hi", "I", "am", "John"]
for k in name_vals:
for i in keys:
for x in values:
dicts[k][i] = x
Expected Output:
{John1: {0: 'John', 1: 'John', 2: 'John', 3: 'John'},
John2: {0: 'John', 1: 'John', 2: 'John', 3: 'John'},
John3: {0: 'John', 1: 'John', 2: 'John', 3: 'John'}}
this is the way with list comprehension
values = ["Hi", "I", "am", "John"]
{ f'Jhon{k+1}': {i: values[3] for i in range(len(values))} for k in range(3)}
Output:
{'Jhon1': {0: 'John', 1: 'John', 2: 'John', 3: 'John'},
'Jhon2': {0: 'John', 1: 'John', 2: 'John', 3: 'John'},
'Jhon3': {0: 'John', 1: 'John', 2: 'John', 3: 'John'}}
you can try this
keys = range(4)
name_vals = ['John'+str(k+1) for k in range(3)]
values = ["Hi", "I", "am", "John"]
dicts = {}
for k in name_vals:
subdict = {}
for i in keys:
subdict[i] = values[i]
dicts[k] = subdict
dicts
output
{'John1': {0: 'Hi', 1: 'I', 2: 'am', 3: 'John'},
'John2': {0: 'Hi', 1: 'I', 2: 'am', 3: 'John'},
'John3': {0: 'Hi', 1: 'I', 2: 'am', 3: 'John'}}
if u want all values to be 'john' then just replace values[i] with values[3]

Appending the counts of lists to a dictionary

I have a large list, which I separated into small sized lists which have elements of occurrences of 1s and 0s, randomly.
Also, the first two lists are made with different parameters from the last two.
Example:
list_of_lists[0] =[1,0,1,1,1,0,1,1,1,0]
list_of_lists[1] =[0,0,0,0,0,0,0,0,0,0]
list_of_lists[2] =[1,1,1,1,1,1,1,1,1,1]
list_of_lists[3] =[0,0,1,1,1,1,1,1,1,0]
I would like to count the occurrences of 1s and 0s in each list, and append them into a dictionary to plot the occurrences.
My trial is as follows:
counts_each = dict()
for i in range(4): #all 4 lists
for k in list_of_lists[i]: #elements of the lists
counts_each[k] = counts_each.get(k, 0) + 1
print(counts_each)
which calculates the general occurrences of the 1s and 0s for the al lists:
{0: 16, 1: 24}
If I do:
list_counts = []
for i in range(4):
counts_each = dict()
for k in list_of_lists[i]:
counts_each[k] = counts_each.get(k, 0) + 1
list_counts.append(counts_each)
print(list_counts)
It does not accumulate all of the counts:
[{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 10},
{0: 10},
{0: 10},
{0: 10},
{0: 10},
{0: 10},
{0: 10},
{0: 10},
{0: 10},
{0: 10},
{1: 10},
{1: 10},
{1: 10},
{1: 10},
{1: 10},
{1: 10},
{1: 10},
{1: 10},
{1: 10},
{1: 10},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7},
{0: 3, 1: 7}]
I would be glad to have some insights of what I am doing wrong.
Thank you.
You can let the collections module do all the counting work for you.
from collections import Counter
list_of_lists = [[] for _ in range(4)]
list_of_lists[0] =[1,0,1,1,1,0,1,1,1,0]
list_of_lists[1] =[0,0,0,0,0,0,0,0,0,0]
list_of_lists[2] =[1,1,1,1,1,1,1,1,1,1]
list_of_lists[3] =[0,0,1,1,1,1,1,1,1,0]
counters = [Counter(l) for l in list_of_lists]
print(*counters, sep="\n")
OUTPUT
Counter({1: 7, 0: 3})
Counter({0: 10})
Counter({1: 10})
Counter({1: 7, 0: 3})
You could use a Dict Comprehension, given your nested list:
list_of_lists = [[1,0,1,1,1,0,1,1,1,0], [0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1], [0,0,1,1,1,1,1,1,1,0]]
use it in this way:
{ idx: {0: lst.count(0), 1: lst.count(1)} for idx, lst in enumerate(list_of_lists) }
#=> {0: {0: 3, 1: 7}, 1: {0: 10, 1: 0}, 2: {0: 0, 1: 10}, 3: {0: 3, 1: 7}}
In the above case I used the index as a key, but you could just use a list comprehension to get a list of dictionaries:
[ {0: lst.count(0), 1: lst.count(1)} for lst in list_of_lists ]
#=> [{0: 3, 1: 7}, {0: 10, 1: 0}, {0: 0, 1: 10}, {0: 3, 1: 7}]
Chris Doyle's answer is excellent, but perhaps your goal is to understand the problem with your solution, specifically.
You have not included your expected output. If I am correct that your issue with your current solution is the repetition of the counts, and you want an output like this:
[{1: 7, 0: 3}, {0: 10}, {1: 10}, {0: 3, 1: 7}]
Then the issue appears to be with the indenting of the line list_counts.append(counts_each). You are doing this each time through the k loop (looping through the items in the list) when I think you want to do it only after finishing the count for a given list:
list_counts = []
for i in range(4):
counts_each = dict()
for k in list_of_lists[i]:
counts_each[k] = counts_each.get(k, 0) + 1
list_counts.append(counts_each)
print(list_counts)

Categories

Resources