Replace values in nested list with dict in Python? - python

I have a nested list:
my_list = ['a','b','c','dog', ['pig','cat'], 'd']
and a dict:
my_dict = {'dog':'c','pig':'a','cat':'d'}
I would like to use the dict, such that I get a list:
new_list = ['a', 'b', 'c', 'c', ['a', 'd'], 'd']
I've tried something like:
new_list = []
for idx1, item1 in enumerate(my_list):
for idx2, item2 in enumerate(item1):
new_list[idx1][idx2] = my_dict[item2]
but I get an error when item2 does not exist in the dict. Is there a better way to do this?

You could write a simple recursive function that uses list comprehension to generate the result. If item on your list is a list then recurse, otherwise use dict.get with default parameter to convert the item:
my_list = ['a','b','c','dog', ['pig','cat'], 'd']
my_dict = {'dog':'c','pig':'a','cat':'d'}
def convert(l, d):
return [convert(x, d) if isinstance(x, list) else d.get(x, x) for x in l]
print(convert(my_list, my_dict))
Output:
['a', 'b', 'c', 'c', ['a', 'd'], 'd']

You look l ike you're trying to substitute into a nested list. Try this function this will recursively swap the values for you:
def replace_vals(_list, my_dict):
new_list = []
for item in _list:
if isinstance(item, list):
new_list.append(replace_vals(item, my_dict))
elif item in my_dict:
new_list.append(my_dict.get(item))
else:
new_list.append(item)
return new_list
print replace_vals(my_list, my_dict)

my_list = ['a','b','c','dog', ['pig','cat'], 'd']
my_dict = {'dog':'c','pig':'a','cat':'d'}
def replace(item):
if item in my_dict:
return my_dict[item]
else:
return item
new_list=[];
for item in my_list:
if isinstance(item,list):
temp_list=[]
for subitem in item:
temp_list.append(replace(subitem))
new_list.append(temp_list)
else:
new_list.append(replace(item))
print new_list
This piece of code will not work if the list inside my_list is nested in itself.

Related

Remove NOT duplicates value from list

The scenario is this something like this:
After joining several lists using:
list1 = ["A","B"]
list2 = ["A","B","C"]
list3 = ["C","D","E"]
mainlist = list1 + list2 + list3
mainlist.sort()
mainlist now looks like that:
mainlist = ['A', 'A', 'B', 'B', 'C', 'C', 'D', 'E']
I would like to remove anything that is not a duplicate value. If the value in question is already present in the list it must not be touched and while if it is present only once in the mainlist I would like to delete it.
I tried to use this approach but seems something isn't working:
for i in mainlist:
if mainlist.count(i) <= 1:
mainlist.remove(i)
else:
continue
but what I return is a list that looks like the following:
mainlist = ['A', 'A', 'B', 'B', 'C', 'C', 'E'] #value "D" is not anymore present. Why?
What i would like to return is a list like that:
mainlist = ['A', 'A', 'B', 'B', 'C', 'C'] #All values NOT duplicates have been deleted
I can delete the duplicates with the below code:
for i in mainlist:
if mainlist.count(i) > 1:
mainlist.remove(i)
else:
continue
and then as a final result:
mainlist = ['A','B','C']
But the real question is: how can I delete the non-duplicates in a list?
You can find duplicates like this:
duplicates = [item for item in mainlist if mainlist.count(item) > 1]
You can use collections.Counter() to keep track of the frequencies of each item:
from collections import Counter
counts = Counter(mainlist)
[item for item in mainlist if counts[item] > 1]
This outputs:
['A', 'A', 'B', 'B', 'C', 'C']
Use collections.Counter to count the list elements. Use list comprehension to keep only the elements that occur more than once. Note that the list does not have to be sorted.
from collections import Counter
list1 = ["A","B"]
list2 = ["A","B","C"]
list3 = ["C","D","E"]
mainlist = list1 + list2 + list3
cnt = Counter(mainlist)
print(cnt)
# Counter({'A': 2, 'B': 2, 'C': 2, 'D': 1, 'E': 1})
dups = [x for x in mainlist if cnt[x] > 1]
print(dups)
# ['A', 'B', 'A', 'B', 'C', 'C']
Another solution, using numpy:
u, c = np.unique(mainlist, return_counts=True)
out = np.repeat(u[c > 1], c[c > 1])
print(out)
Prints:
['A' 'A' 'B' 'B' 'C' 'C']
Your problem lies in you operating on the while iterating over it. After removing the "D" the loops stops because there are no more elements in the list as the "E" at index 6.
Create a copy of the list and only operate on that list:
new_list = list(mainlist)
for i in mainlist:
if mainlist.count(i) <= 1:
new_list.remove(i)
else:
continue
If you want to output only a list of duplicate elements in your lists, you can use sets and a comprehension to keep only the duplicates.
list1 = ["A","B"]
list2 = ["A","B","C"]
list3 = ["C","D","E"]
fulllist = list1 + list2 + list3
fullset = set(list1) | set(list2) | set(list3)
dups = [x for x in fullset if fulllist.count(x) > 1]
print(dups) # ['A', 'C', 'B']

Search for string in a nested list (python)

I have a nested_list = [['a'], ['b', 'c'], ['b','d']] and i have target element of 'b', how would i search through this list to return list containing element, hence ['b', 'c'],['b','d'] ?
I have tried but it is only giving me ['b', 'c']:
for elem in nest_list:
for item in elem:
if 'b' in item:
return elem
This is because you return the item, and once the return statement is reached, this loop isn't run again. If you were to replace return elem with print(elem), you would see both results being printed out.
If you want to return both values, then you can create another array which appends your results and then returns it outside the for loop:
returnList = []
for elem in nest_list:
if 'b' in elem:
returnList.append(elem)
return returnList
Note that you can also remove one of the for loops since in checks within a list.
for elem in nest_list:
for item in elem:
if 'b' in item:
print(elem,end=",")
You can use list comprehension:
nested_list = [['a'], ['b','c'], ['b','d']]
output = [sublst for sublst in nested_list if 'b' in sublst]
print(output) # [['b', 'c'], ['b', 'd']]

Making list that takes in value if value appears more than once

If my list has values that appears more than once I want to do the following:
my_list = ['a','b','c','a','a','b']
I want that my_list becomes ['a','b','c']
and at the same time new_list = ['a','a','b']
I have started with the code but can't manage to finish it:
def func(word):
tgt = 1
found = []
lst = [1,2,3,45,6,1]
if lst.count(word)> 1:
found.append(word)
return found, lst
print(func(1))
You can iterate through the list, store the element in one list if it is not visited or in a new list if it is already visited:
my_list = ['a','b','c','a','a','b']
visited, lst, new_list = set(), [], []
for x in my_list:
if x not in visited:
lst.append(x)
visited.add(x)
else:
new_list.append(x)
print(lst, new_list)
# ['a', 'b', 'c'] ['a', 'a', 'b']
my_list = ['a','b','c','a','a','b']
new_list = my_list.copy()
my_list = list(set(my_list))
my_list.sort()
# remove unique items from new_list
for item in my_list:
new_list.pop(new_list.index(item))
I'm going to use a collections.Counter() to count up the occurrences of each items in the list. At that point the keys() become your new my_list and then we will use some list multiplication to construct your new_list.
import collections
data = ['a','b','c','a','a','b']
counted = collections.Counter(data)
At this point finding your new my_list is dead simple:
my_list = list(counted)
print(my_list)
gives you:
['a', 'b', 'c']
Now we can leverage the fact that ['a'] * 4 == ['a', 'a', 'a', 'a'] to construct a list from they keys of counted based on the number of times they were identified.
new_list = []
for key, value in counted.items():
if value > 1:
new_list.extend([key]*(value-1))
print(new_list)
This will give us back:
['a', 'a', 'b']
Full Solution:
import collections
data = ['a','b','c','a','a','b']
counted = collections.Counter(data)
my_list = list(counted)
new_list = []
for key, value in counted.items():
if value > 1:
new_list.extend([key]*(value-1))
print(my_list, new_list)
lst = ["a","b","a","c","d","b"]
new_list=[]
for i in lst:
if i not in new_list: # check the new list if values repeat or not
new_list.append(i) # add the repeating values in new list
for i in new_list:
if i in lst:
lst.remove(i) # remove the repeating values from first list
print(lst,new_list)
at first you can add the repeating values in a different list then remove these values from your first list.
l = ['a', 'b', 'c', 'a', 'c']
arr = []
for x in l:
if x not in a:
arr.append(x)
# now arr only have the non repeating elements of the array l

How to number elements in a list of string and return a new list?

So I have a list of strings. I want to create a new list of string which turns the same string into a new string and name it "A". If there's a different string in the list, name it "B" and so on.
If the string is:
['F4','A3','F4','B5','A3','K2']
Then it should give me a result of:
['A','B','A','C','B','D']
I don't know how to start the code and can only think of something like a dictionary.
dict = {}
result = []
for line in list1:
if line not in dict:
dict.update({line:str(chr(65+len(dict)))})
result.append(dict.get(line))
Then I don't know how to continue. Any help will be appreciated.
You can make an iterator of ascii upper-case strings and pull them off one-at-a-time in a defaultdict constructor. One you have that, it's just a list comprehension. Something like:
import string
from collections import defaultdict
keys = iter(string.ascii_uppercase)
d = defaultdict(lambda: next(keys))
l = ['F4','A3','F4','B5','A3','K2']
[d[k] for k in l]
# ['A', 'B', 'A', 'C', 'B', 'D']
import string
mapping = {}
offset = 0
for item in l:
if item in mapping:
continue
mapping[item] = string.ascii_uppercase[offset]
offset += 1
[mapping.get(item) for item in l]
Output
['A', 'B', 'A', 'C', 'B', 'D']
You can create a simple class to store the running results:
import string
class L:
def __init__(self):
self.l = {}
def __getitem__(self, _v):
if (val:=self.l.get(_v)) is not None:
return val
self.l[_v]= (k:=string.ascii_uppercase[len(self.l)])
return k
l = L()
vals = ['F4','A3','F4','B5','A3','K2']
result = [l[i] for i in vals]
Output:
['A', 'B', 'A', 'C', 'B', 'D']

count sublists that has a specific term in python

I'm a newbie I want to write a function that outputs the count of sublists that contain a particular element. But my function just outputs the total count of that particular term in all the sublists.
My function:
def count(myList):
tmp = []
d = {}
for item in myList: tmp += item
for key in tmp: d[key] = d.get(key, 0) + 1
return d
My output:
>>res = count_doc_frequencies([['a', 'b', 'a'], ['a', 'b', 'c'], ['a']])
>>res['a']
4
>>res['b']
2
Desired output:
>>res = count_doc_frequencies([['a', 'b', 'a'], ['a', 'b', 'c'], ['a']])
>>res['a']
3
As 'a' is present in 3 sublists..
can anyone help me modify my function to achieve the desired output ??
lst = [['a', 'b', 'a'], ['a', 'b', 'c'], ['a']]
def count(lst):
# declare dictionary that we are going to return
foo = {}
# iterate sublist
for sublist in lst:
# make sublist into unique element list
sublist = list(set(sublist))
for element in sublist:
# if element found in foo dic, increment
if element in foo:
foo[element] += 1
# else, init with 1
else:
foo[element] = 1
return foo
res = count(lst)
print res
You should change this statement
tmp += item
to
tmp += set(item)
This will eliminate the duplication count of elements in your sublists.
Another way to write this will be
def count(myList,ele):
tmp = []
key = 0
for item in myList:
if ele in item:
key += 1
return key

Categories