How to add index to a list inside a dictionary - python

I have a dictionary here:
dict = {'A':['1','1','1','1','1'], 'B':['2','2'], 'C':['3','3','3','3']}
What is the necessary process to get the following result?
dict = {'A':['1_01','1_02','1_03','1_04','1_05'], 'B':['2_01','2_02'], 'C':['3_01','3_02','3_03','3_04']}
I have been learning python for quite a while now but dictionary is kind of new to me.

As others mentioned, refrain from using built-in keywords as variable names, such as dict. I kept it for simplicity on your part.
This is probably the most pythonic way of doing it (one line of code):
dict = {key:[x+"_0"+str(cnt+1) for cnt,x in enumerate(value)] for key,value in dict.items()}
You could also iterate through each dictionary item, and then each list item and manually change the list names as shown below:
for key,value in dict.items():
for cnt,x in enumerate(value):
dict[key][cnt] = x+"_0"+str(cnt+1)
Also, as some others have mentioned, if you want numbers greater than 10 to save as 1_10 rather than 1_010 you can you an if/else statement inside of the list comprehension...
dict = {key:[x+"_0"+str(cnt+1) if cnt+1 < 10 else x+"_"+str(cnt+1) for cnt,x in enumerate(value)] for key,value in dict.items()}

First iterate on keys.
Then loop on keys you are getting on key like for 'A' value is ['1','1','1','1','1'] then we can change the element at ['1','1','1','1','1']
enumerate() helps you iterate on index,value then index starts with zero as per your expected output add 1 to index. As you want the trailing 0 before each count we did '%02d'% (index+1)
Like this:
dict = {'A':['1','1','1','1','1'], 'B':['2','2'], 'C':['3','3','3','3']}
for i in dict.keys(): #iterate on keys
for index,val in enumerate(dict[i]): #took value as we have key in i
element='%02d'% (index+1) #add trailing 0 we converted 1 to int 01
dict[i][index]=val+"_"+ str(element) #assign new value with converting integer to string
print(dict)
Output:
{'A': ['1_01', '1_02', '1_03', '1_04', '1_05'], 'C': ['3_01', '3_02', '3_03', '3_04'], 'B': ['2_01', '2_02']}

Use enumerate to iterate over list keeping track of index:
d = {'A':['1','1','1','1','1'], 'B':['2','2'], 'C':['3','3','3','3']}
newd = {}
for k, v in d.items():
newd[k] = [f'{x}_0{i}' for i, x in enumerate(v, 1)]
print(newd)
Also a dictionary-comprehension:
d = {k: [f'{x}_0{i}' for i, x in enumerate(v, 1)] for k, v in d.items()}
Note: Don't name your dictionary as dict because it shadows the built-in.

d= {'A':['1','1','1','1','1'], 'B':['2','2'], 'C':['3','3','3','3']}
{x:[j + '_'+ '{:02}'.format(i+1) for i,j in enumerate(y)] for x,y in d.items()}

adict = {'A':['1','1','1','1','1'], 'B':['2','2'], 'C':['3','3','3','3'], 'D': '23454'}
newdict = {}
for i,v in adict.items():
if isinstance(v, list):
count = 0
for e in v:
count += 1
e += '_0' + str(count)
newdict[i] = newdict.get(i, [e]) + [e]
else:
newdict[i] = newdict.get(i, v)
print (newdict)
#{'A': ['1_01', '1_01', '1_02', '1_03', '1_04', '1_05'], 'B': ['2_01', '2_01', '2_02'], 'C': ['3_01', '3_01', '3_02', '3_03', '3_04'], 'D': '23454'}
This solution will check for whether your value in the dictionary is a list before assigning an index to it

You can use a dictcomp:
from itertools import starmap
d = {
'A': ['1', '1', '1', '1', '1'],
'B': ['2', '2'],
'C': ['3', '3', '3', '3']
}
f = lambda x, y: '%s_%02d' % (y, x)
print({k: list(starmap(f, enumerate(v, 1))) for k, v in d.items()})
# {'A': ['1_01', '1_02', '1_03', '1_04', '1_05'], 'B': ['2_01', '2_02'], 'C': ['3_01', '3_02', '3_03', '3_04']}

Related

Convert string to dictionary with list of values

What is the best way to convert a string to dictionary with value of dictionary as a list
for example
str = "abc=1,abc=2,abc=3,xyz=5,xyz=6"
i need the output as:
d = {"abc":["1","2","3"],"xyz":["5","6"]}
I'm very new to python.
my code:
d = {k: [v] for k, v in map(lambda item: item.split('='), s.split(","))}
Here is the solution with dict.setdefault method.
>>> help({}.setdefault)
Help on built-in function setdefault:
setdefault(key, default=None, /) method of builtins.dict instance
Insert key with a value of default if key is not in the dictionary.
Return the value for key if key is in the dictionary, else default.
>>> your_str = "abc=1,abc=2,abc=3,xyz=5,xyz=6"
>>>
>>> result = {}
>>>
>>> for pair in your_str.split(","):
... name, val = pair.split("=")
... result.setdefault(name, []).append(val)
>>> result
{'abc': ['1', '2', '3'], 'xyz': ['5', '6']}
You could also use defaultdict with default factory as list
>>> from collections import defaultdict
>>>
>>> your_str = "abc=1,abc=2,abc=3,xyz=5,xyz=6"
>>>
>>> result = defaultdict(list)
>>> for pair in str.split(","):
... name, val = pair.split("=")
... result[name].append(val)
...
>>> dict(result)
{'abc': ['1', '2', '3'], 'xyz': ['5', '6']}
The reason the code you have tried already isn't giving you the desired result is the fact that you are overwriting the value assigned to each key as you iterate over the list. What you need to do is append to the value already assigned to the key - except if the key doesn't exist, in which case you need to initialise that key.
This would be one way to go:
s1 = "abc=1,abc=2,abc=3,xyz=5,xyz=6"
list1 = [(each.split('=')) for each in s1.split(',')]
d = {}
for key, val in list1:
if key in d.keys():
d[key].append(val)
else:
d[key] = [val]
print (d)
#result: {'abc': ['1', '2', '3'], 'xyz': ['5', '6']}
You could simplify this and eliminate the if-else by using defaultdict, like so:
from collections import defaultdict
d = defaultdict(lambda: [])
s1 = "abc=1,abc=2,abc=3,xyz=5,xyz=6"
list1 = [(each.split('=')) for each in s1.split(',')]
for key, val in list1:
d[key].append(val)
print (d)
#result: {'abc': ['1', '2', '3'], 'xyz': ['5', '6']}
# initialize a dictionary
d = {}
# split the string (my_str) according to "," in order to get pairs such as 'abc/1' and 'xyz/5' in a list
for elt in my_str.split(",") :
# for each string of the list, split according to '/' to get the pairs ['abc', 1]
# complete the dictionary
if elt.split('/')[0] not in d.keys():
d[elt.split('/')[0]] = [elt.split('/')[1]]
else :
d[elt.split('/')[0]].append(elt.split('/')[1])

Appending dictionary to list with different value same key

I have a list of dictionaries, that have same keys and some have different values for those keys. I am trying to append the dictionaries that have different values from the list to keep track of the different values and I would concatenate the values of other keys. For example, I am storing 'a' keys with same values and concatenating the 'b' values that have same 'a':'1'
input list: d = [{'a': '1', 'b': '3'}, {'a': '2', 'b': '4'}, {'a': '1', 'b':'5'}]
output list: p = [{'a':'1', 'b': '35'}, {'a': '2', 'b': '4'}]
So far, I tried the following code, but it doesnt recognize the different values
length = len(p)
j = 0
for i in d:
while j < length:
if p[j]['a'] is not i['a']:
p.append({'a', p[j]['a']})
else:
p[j]['b'] += i['b']
j += 1
j = 0
any tips would be appreciated
Use a dictionary that has the a values as its keys so you don't have to loop through the result list for a matching a.
temp_dict = {}
for item in d:
if item['a'] in temp_dict:
temp_dict[item['a']]['b'] += item['b']
else:
temp_dict[item['a']] = item.copy()
p = list(temp_dict.values())

Python: Create a dictionary where keys have multiple values

The problem that I have is hard to explain, easy to understand:
I have a list of tuples:
L=[('a','111'),('b','222'),('a','333'),('b','444')]
from this list I want to createa dictionary where the keys are the first elements of the tuples ('a' and 'b') and the values associated are in a list:
expected output:
{'a':['111','333'],'b':['222','444']}
How can I solve this problem?
d={}
for x in range (len(L)):
d[L[x][0]]=[L[x][1]]
return d
but as you can easy understand, the output won't be complete since the list will show just the last value associated to that key in L
You can use setdefault() to set the key in the dict the first time. Then append your value:
L=[('a','111'),('b','222'),('a','333'),('b','444')]
d = {}
for key, value in L:
d.setdefault(key, []).append(value)
print(d)
# {'a': ['111', '333'], 'b': ['222', '444']}
You have to append L[x][1] to an existing list, not replace whatever was there with a new singleton list.
d={}
for x in range (len(L)):
if L[x][0] not in d:
d[L[x][0]] = []
d[L[x][0]].append(L[x][1])
return d
A defaultdict makes this easier:
from collections import defaultdict
d = defaultdict(list)
for x in range(len(L)):
d[L[x][0]].append(L[x][1])
return d
A more idiomatic style of writing this would be to iterate directly over the list and unpack the key and value immediately:
d = defaultdict(list)
for key, value in L:
d[key].append(value)
You can try this:
L = [('a','111'),('b','222'),('a','333'),('b','444')]
my_dict = {}
for item in L:
if item[0] not in my_dict:
my_dict[item[0]] = []
my_dict[item[0]].append(item[1])
print(my_dict)
Output:
python your_script.py
{'a': ['111', '333'], 'b': ['222', '444']}
As pointed by #chepner, you can use defaultdict to.
Basically, with defaultdict you'll not need to check if there is no key yet in your dict.
So it would be:
L = [('a','111'),('b','222'),('a','333'),('b','444')]
my_dict = defaultdict(list)
for item in L:
my_dict[item[0]].append(item[1])
print(my_dict)
And the output:
defaultdict(<class 'list'>, {'a': ['111', '333'], 'b': ['222', '444']})
And if you want to get a dict from the defaultdict, you can simply create a new dict from it:
print(dict(my_dict))
And the output will be:
{'a': ['111', '333'], 'b': ['222', '444']}

Python Dictionary using Lists as Values, find other Keys with same values

Say I have the following dictionary.
>> sample_dict = {"1": ['a','b','c'], "2": ['d','e','f'], "3": ['g','h','a']}
I would like to find a way that would look at the values of each of the keys and return whether or not the value lists have the a duplicate variable inside.
For example it would output:
>> [["1","3"] , ['a']]
I've looked at a few of the posts here and tried to use and/or change them to accomplish this, however none of what I have found has worked as intended. They would work if it was as follows:
>> sample_dict = {"1": ['a','b','c'], "2": ['d','e','f'], "3": ['a','b','c']}
but not if only a single value within the list was the same.
You could use another dictionary to map the values to the lists of corresponding keys. Then just select the values that map to more than one key, e.g.:
from collections import defaultdict
sample_dict = {'1': ['a','b','c'], '2': ['d','e','f'], '3': ['g','h','a']}
d = defaultdict(list) # automatically initialize every value to a list()
for k, v in sample_dict.items():
for x in v:
d[x].append(k)
for k, v in d.items():
if len(v) > 1:
print([v, k])
Output:
[['1', '3'], 'a']
If the list elements are hashable, you can use .setdefault to build an inverse mapping like so:
>>> sample_dict = {"1": ['a','b','c'], "2": ['d','e','f'], "3": ['g','h','a']}
>>> aux = {}
>>> for k, v in sample_dict.items():
... for i in v:
... aux.setdefault(i, []).append(k)
...
>>> [[v, k] for k, v in aux.items() if len(v) > 1]
[[['1', '3'], 'a']]
Dictionaries map from keys to values, not from values to keys. But you can write a function for one-off calculations. This will incur O(n) time complexity and is not recommended for larger dictionaries:
def find_keys(d, val):
return [k for k, v in d.items() if val in v]
res = find_keys(sample_dict, 'a') # ['1', '3']
If you do this often, I recommend you "invert" your dictionary via collections.defaultdict:
from collections import defaultdict
dd = defaultdict(list)
for k, v in sample_dict.items():
for w in v:
dd[w].append(k)
print(dd)
defaultdict(<class 'list'>, {'a': ['1', '3'], 'b': ['1'], 'c': ['1'], 'd': ['2'],
'e': ['2'], 'f': ['2'], 'g': ['3'], 'h': ['3']})
This costs O(n) for the inversion, as well as additional memory, but now allows you to access the keys associated with an input value in O(1) time, e.g. dd['a'] will return ['1', '3'].
You can use defaultdict from collections module to do this
for example,
from collections import defaultdict
sample_dict = {"1": ['a','b','c'], "2": ['d','e','f'], "3": ['g','h','a']}
d = defaultdict(list)
for keys, vals in sample_dict.items():
for v in vals:
d[v].append(keys)
print(d)
d will return a dict, where the keys will be the values that are repeated and values will be the list in which they were repeated in
The output of above code is defaultdict(list,{'a': ['1', '3'],'b': ['1'],'c': ['1'],'d': ['2'],'e': ['2'],'f': ['2'],'g': ['3'],'h': ['3']})
​
Although it IS possible to get form in which you desired the output to be in, but it is not generally recommended because we are trying to get what character get repeated in which list, that feels like a job of a dictionary

py3k: mapping dictionary (string->number) into list (of strings)

Assume we have dictionary that translates strings into numbers.
How to reverse it into list ?
Let assume, we can fill not mapped numbers with empty string ''.
Here example how it works:
>>> dic_into_list({'x':0, 'z':2, 'w':3})
['x', '', 'z', 'w']
d = {'x':0, 'z':2, 'w':3}
lst = [""] * (max(d.values()) + 1)
for k, v in d.items():
lst[v] = k
print(lst)
prints
['x', '', 'z', 'w']
The simplest way is to flip the dict and then iterate up to the maximum value (now key) in the dict:
original = {'x':0, 'z':2, 'w':3}
d = dict((v, k) for k, v in original.iteritems())
print [d.get(i, '') for i in range(max(d) + 1)]
I share my current solution: (I look for shorter and cleared implementation in other posts):
def dic_into_list(dic):
maxindex = max([v for i,v in dic.items()])
dicrev = {num:name for name,num in dic.items()}
l=[]
for i in range(0,maxindex+1):
if i in dicrev:
l.append(dicrev[i])
else:
l.append('')
return l

Categories