Data manipulation with Dictionaries in python - python

I am working with dictionaries and want to solve this custom problem wherein I want values in my dictionary to be in the same position as in my_list. In case, we don't have the value in the dictionary it should place with '-'
All the values in the dictionary are available in my_list.
my_list = ['a', 'b', 'c', 'd']
d = {'x':['a', 'b', 'd'], 'y':['a', 'c'], 'z': ['d', 'b']}
expected output:
{'x':['a', 'b', '-', 'd'], 'y':['a', '-', 'c', '-'], 'z':['-', 'b', '-', 'd']}

You can iterate over my_list and check each value exists in list that exist in d. We can change the dict in-place like below:
my_list = ['a', 'b', 'c', 'd']
d = {'x':['a', 'b', 'd'], 'y':['a', 'c'], 'z': ['d', 'b']}
for key, lst in d.items():
d[key] = [val if val in lst else '-' for val in my_list]
print(d)
# {'x': ['a', 'b', '-', 'd'], 'y': ['a', '-', 'c', '-'], 'z': ['-', 'b', '-', 'd']}

from collections import OrderedDict
my_list=['a','b','c','d']
d={'x':['a','b','d'],'y':['a','c'],'z':['d','b']}
z=list(d)
new=OrderedDict.fromkeys(z,'-')
for i in d.keys():
dict = OrderedDict.fromkeys(my_list,'-')
for j in d[i]:
dict[j]=j
new[i]=list(dict.values())
print(new)

Related

Group items if trailed by string [duplicate]

I have a list called list_of_strings that looks like this:
['a', 'b', 'c', 'a', 'd', 'c', 'e']
I want to split this list by a value (in this case c). I also want to keep c in the resulting split.
So the expected result is:
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]]
Any easy way to do this?
You can use more_itertoools+ to accomplish this simply and clearly:
from more_itertools import split_after
lst = ["a", "b", "c", "a", "d", "c", "e"]
list(split_after(lst, lambda x: x == "c"))
# [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
Another example, here we split words by simply changing the predicate:
lst = ["ant", "bat", "cat", "asp", "dog", "carp", "eel"]
list(split_after(lst, lambda x: x.startswith("c")))
# [['ant', 'bat', 'cat'], ['asp', 'dog', 'carp'], ['eel']]
+ A third-party library that implements itertools recipes and more. > pip install more_itertools
stuff = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
You can find out the indices with 'c' like this, and add 1 because you'll be splitting after it, not at its index:
indices = [i + 1 for i, x in enumerate(stuff) if x == 'c']
Then extract slices like this:
split_stuff = [stuff[i:j] for i, j in zip([0] + indices, indices + [None])]
The zip gives you a list of tuples analogous to (indices[i], indices[i + 1]), with the concatenated [0] allowing you to extract the first part and [None] extracting the last slice (stuff[i:])
You could try something like the following:
list_of_strings = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
output = [[]]
for x in list_of_strings:
output[-1].append(x)
if x == 'c':
output.append([])
Though it should be noted that this will append an empty list to your output if your input's last element is 'c'
def spliter(value, array):
res = []
while value in array:
index = array.index(value)
res.append(array[:index + 1])
array = array[index + 1:]
if array:
# Append last elements
res.append(array)
return res
a = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
print(spliter('b',a))
# [['a', 'b'], ['c', 'a', 'd', 'c', 'e']]
print(spliter('c',a))
# [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
What about this. It should only iterate over the input once and some of that is in the index method, which is executed as native code.
def splitkeep(v, c):
curr = 0
try:
nex = v.index(c)
while True:
yield v[curr: (nex + 1)]
curr = nex + 1
nex += v[curr:].index(c) + 1
except ValueError:
if v[curr:]: yield v[curr:]
print(list(splitkeep( ['a', 'b', 'c', 'a', 'd', 'c', 'e'], 'c')))
result
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
I wasn't sure if you wanted to keep an empty list at the end of the result if the final value was the value you were splitting on. I made an assumption you wouldn't, so I put a condition in excluding the final value if it's empty.
This has the result that the input [] results in only [] when arguably it might result in [[]].
How about this rather playful script:
a = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
b = ''.join(a).split('c') # ['ab', 'ad', 'e']
c = [x + 'c' if i < len(b)-1 else x for i, x in enumerate(b)] # ['abc', 'adc', 'e']
d = [list(x) for x in c if x]
print(d) # [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
It can also handle beginnings and endings with a "c"
a = ['c', 'a', 'b', 'c', 'a', 'd', 'c', 'e', 'c']
d -> [['c'], ['a', 'b', 'c'], ['a', 'd', 'c'], ['e', 'c']]
list_of_strings = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
value = 'c'
new_list = []
temp_list = []
for item in list_of_strings:
if item is value:
temp_list.append(item)
new_list.append(temp_list[:])
temp_list.clear()
else:
temp_list.append(item)
if (temp_list):
new_list.append(temp_list)
print(new_list)
You can try using below snippet. Use more_itertools
>>> l = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
>>> from more_itertools import sliced
>>> list(sliced(l,l.index('c')+1))
Output is:
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]

Group all keys in dict that have identical values, when the values are lists

I have a dict:
my_dict = {
'train_1': ['a', 'b','c'],
'train_2': ['a', 'b', 'c', 'd'],
'train_3': ['a', 'b', 'c', 'd'],
'train_4': ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],
'train_5': ['a', 'b', 'c', 'd', 'e', 'f'],
'train_6': ['a', 'b', 'c', 'd']
}
I need to find all keys in the dict that have identical lists.
The output should be:
{
'group_1': ['train1'],
'group_2': ['train_2', 'train_3', 'train_6'],
'group_3': ['train_4'],
'group_4': ['train_5'],
}
I can use something like this for the task when the values in the dict are not lists:
flipped = {}
for key, value in my_dict.items():
print(value)
if value not in flipped:
flipped[value] = [key]
else:
flipped[value].append(key)
But how can I achieve this when the values are lists?
Continuing from the comments, you could change the lists to tuple and then use them as the keys:
my_dict = {
'train_1': ['a', 'b','c'],
'train_2': ['a', 'b', 'c', 'd'],
'train_3': ['a', 'b', 'c', 'd'],
'train_4': ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],
'train_5': ['a', 'b', 'c', 'd', 'e', 'f'],
'train_6': ['a', 'b', 'c', 'd']
}
flipped = {}
for key, value in my_dict.items():
if tuple(value) not in flipped:
flipped[tuple(value)] = [key]
else:
flipped[tuple(value)].append(key)
print(flipped)
OUTPUT:
{('a', 'b', 'c'): ['train_1'], ('a', 'b', 'c', 'd'): ['train_3', 'train_6', 'train_2'], ('a', 'b', 'c', 'd', 'e', 'f'): ['train_5'], ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h')
: ['train_4']}
EDIT:
once, filtered. you could iterate over the new dict and assign the desired keys:
grouped_dct = {}
i = 1
for k,v in flipped.items():
grouped_dct['group_' + str(i)] = v
i += 1
print(grouped_dct)
OUTPUT:
{'group_1': ['train_4'], 'group_2': ['train_5'], 'group_3': ['train_2', 'train_6', 'train_3'], 'group_4': ['train_1']}
if order of element in the list matters then below should work for you.
flipped = {}
for key, value in my_dict.items():
print(value)
newVal = ''.join(x for x in value)
if newVal not in flipped:
flipped[newVal] = [key]
else:
flipped[newVal].append(key)
print(flipped)

Converting paired list values to dictionary

I have a list of pairs like the following one:
[['A', 'B'],
['C', 'E'],
['F', 'D'],
['C', 'D'],
['D', 'E'],
['G', 'E'],
['B', 'A'],
['H', 'G'],
['A', 'F'],
['E', 'A']]
I want to generate a dictionary with the first value in each pair as keys and the second one as value like the following:
{'A': ['B', 'F'],
'B': ['A'],
'C': ['E', 'D'],
'D': ['E'],
'E': ['A'],
'F': ['D', 'E'],
'G': ['E'],
'H': ['G']}
I used the following code, but didn't reached the desired outcome:
keys = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
graph = {}
graph = graph.fromkeys(keys, [])
for row in pairs:
(graph[row[0]]).append(row[1])
dict.fromkeys will set all your values to the same list object! Use dict.setdefault instead which will create a new list for each unknown key:
graph = {}
for row in pairs:
graph.setdefault(row[0], []).append(row[1])
Alternatively, use a collection.defaultdict
from collections import defaultdict
graph = defaultdict(list)
for row in pairs:
graph[row[0]].append(row[1])
Or, more elegantly:
for v1, v2 in in pairs:
graph[v1].append(v2)

Split List By Value and Keep Separators

I have a list called list_of_strings that looks like this:
['a', 'b', 'c', 'a', 'd', 'c', 'e']
I want to split this list by a value (in this case c). I also want to keep c in the resulting split.
So the expected result is:
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]]
Any easy way to do this?
You can use more_itertoools+ to accomplish this simply and clearly:
from more_itertools import split_after
lst = ["a", "b", "c", "a", "d", "c", "e"]
list(split_after(lst, lambda x: x == "c"))
# [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
Another example, here we split words by simply changing the predicate:
lst = ["ant", "bat", "cat", "asp", "dog", "carp", "eel"]
list(split_after(lst, lambda x: x.startswith("c")))
# [['ant', 'bat', 'cat'], ['asp', 'dog', 'carp'], ['eel']]
+ A third-party library that implements itertools recipes and more. > pip install more_itertools
stuff = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
You can find out the indices with 'c' like this, and add 1 because you'll be splitting after it, not at its index:
indices = [i + 1 for i, x in enumerate(stuff) if x == 'c']
Then extract slices like this:
split_stuff = [stuff[i:j] for i, j in zip([0] + indices, indices + [None])]
The zip gives you a list of tuples analogous to (indices[i], indices[i + 1]), with the concatenated [0] allowing you to extract the first part and [None] extracting the last slice (stuff[i:])
You could try something like the following:
list_of_strings = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
output = [[]]
for x in list_of_strings:
output[-1].append(x)
if x == 'c':
output.append([])
Though it should be noted that this will append an empty list to your output if your input's last element is 'c'
def spliter(value, array):
res = []
while value in array:
index = array.index(value)
res.append(array[:index + 1])
array = array[index + 1:]
if array:
# Append last elements
res.append(array)
return res
a = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
print(spliter('b',a))
# [['a', 'b'], ['c', 'a', 'd', 'c', 'e']]
print(spliter('c',a))
# [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
What about this. It should only iterate over the input once and some of that is in the index method, which is executed as native code.
def splitkeep(v, c):
curr = 0
try:
nex = v.index(c)
while True:
yield v[curr: (nex + 1)]
curr = nex + 1
nex += v[curr:].index(c) + 1
except ValueError:
if v[curr:]: yield v[curr:]
print(list(splitkeep( ['a', 'b', 'c', 'a', 'd', 'c', 'e'], 'c')))
result
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
I wasn't sure if you wanted to keep an empty list at the end of the result if the final value was the value you were splitting on. I made an assumption you wouldn't, so I put a condition in excluding the final value if it's empty.
This has the result that the input [] results in only [] when arguably it might result in [[]].
How about this rather playful script:
a = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
b = ''.join(a).split('c') # ['ab', 'ad', 'e']
c = [x + 'c' if i < len(b)-1 else x for i, x in enumerate(b)] # ['abc', 'adc', 'e']
d = [list(x) for x in c if x]
print(d) # [['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]
It can also handle beginnings and endings with a "c"
a = ['c', 'a', 'b', 'c', 'a', 'd', 'c', 'e', 'c']
d -> [['c'], ['a', 'b', 'c'], ['a', 'd', 'c'], ['e', 'c']]
list_of_strings = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
value = 'c'
new_list = []
temp_list = []
for item in list_of_strings:
if item is value:
temp_list.append(item)
new_list.append(temp_list[:])
temp_list.clear()
else:
temp_list.append(item)
if (temp_list):
new_list.append(temp_list)
print(new_list)
You can try using below snippet. Use more_itertools
>>> l = ['a', 'b', 'c', 'a', 'd', 'c', 'e']
>>> from more_itertools import sliced
>>> list(sliced(l,l.index('c')+1))
Output is:
[['a', 'b', 'c'], ['a', 'd', 'c'], ['e']]

Given a dictionary, how to replace an item in the list?

Given a dictionary such as:
sample_dict = {'test':['a', 'b', 'c', 'd', 'e']}
how do I change an item in the list with something else.
example:
def replace_item(sample_dict, item, new_item):
pass
>>> replace_item({'test':['a', 'b', 'c', 'd', 'e']}, 'd', 'f')
>>> {'test':['a', 'b', 'c', 'f', 'e']}
You can simply retrieve the list and modify it, since the dictionary only stores a reference to the list, not the list itself.
sample_dict = {'test': ['a', 'b', 'c', 'd', 'e']}
def replace_item(sample_dict, item, new_item):
list = sample_dict['test']
list[list.index(item)] = new_item
replace_item(sample_dict, 'd', 'f')
# {'test': ['a', 'b', 'c', 'f', 'e']}

Categories