Python removal of items after iteration - python

Why is my code not working? I can't figure it out
matchList = [['g', 'h', 'i'], ['a', 'b', 'c'] ... ]]
myList = []
for i in match_list:
for j in i:
for word in first_list:
if j in word:
myList.append(j)
match_list.remove(j)
I am getting the error ValueError: list.remove(x): x not in list
EDIT:
first_list = ['i', 'am', 'an', 'old', 'man']

You want:
i.remove(j)
match_list is a list of lists

list_of_lists = [['g', 'h', 'i'], ['a', 'b', 'c'] ... ]]
first_list = ['i', 'am', 'an', 'old', 'man']
myList = []
for current_list in list_of_lists:
for item in current_list:
for word in first_list:
if item in word:
myList.append(item)
list_of_lists.remove(item)
I edited your code so it would read more sensibly, to me, so I can think I know what you're trying to do.
In my mind, you are reading through a list, from within a set of lists to check to see if an item from that "sublist" is in another list (first_list).
If the item is in one of the words in first list, you are trying to remove the "sublist" from list_of_lists, correct? If so, that's where you are getting your error. Say you are on the first iteration of the set of lists, and you are checking to see if the letter "i" from the first sublist in list_of_lists is in the first word from first_list. It should evaluate to true. At that point, you are then telling Python the following in plain english, "Python, remove the item from list_of_lists that has a value of i." However, because list_of_lists contains lists, that won't work, because none of the values within list_of_lists are strings, just lists.
What you need to do is specify the list you are currently iterating on, which will be represented by current_list in the above code.
So maybe instead of
list_of_lists.remove(item)
or rather in your code
match_list.remove(j)
try
list_of_lists.remove(current_list)
or rather in your code
match_list.remove(i).
I have a feeling you are going to experience other errors with the iterations that will likely remain in some scenarios if you get another match, but that's not the problem you're having now....

Try this:
btw: you used matchList and match_list in your post. I corrected that for my answer to make it consistent.
matchList = [['g', 'h', 'i'], ['a', 'b', 'c']]
myList = []
first_list = ['i', 'am', 'an', 'old', 'man']
for i in matchList:
for j in i:
for word in first_list:
if j in word:
myList.append(j)
for s in myList:
if s in i:
i.remove(s)
print(myList)
['i', 'a', 'a', 'a']
print(matchList)
[['g', 'h'], ['b', 'c']]

You could try a list comprehesion after iteration.
matchList = [['g', 'h', 'i'], ['a', 'b', 'c']]
first_list = ['i', 'am', 'an', 'old', 'man']
myList = []
for i in matchList:
for j in i:
for word in first_list:
if j in word:
myList.append(j)
# Remove items from sublists
matchList = [[j for j in matchList[i] if j not in myList] for i in range(len(matchList))]
Output:
In [7]: myList
Out[7]: ['i', 'a', 'a', 'a']
In [8]: matchList
Out[8]: [['g', 'h'], ['b', 'c']]

Related

Change the values in the nested list according to the specified index list

How to change the values in nested list
How to change the values in the list base on the indexes To clarify, I originally have the_list
the_list = [['a','a','a'],['b','b','b'],['b','b','b'],['c','c','c']]
However, I would like to change the values in the_list above that have the index/position in the indexA
indexA = [(0,2),(1,2),(0,1)]
which I would like to change the following index of the_list to 'hi'
the_list[0][2]
the_list[1][2]
the_list[0][1]
Therefore, the expected output is
the_list = [['a', 'hi', 'hi'], ['b', 'b', 'hi'], ['b', 'b', 'b'],['c', 'c', 'c']]
Currently I'm doing it manually by what follows:
the_list = [['a','a','a'],['b','b','b'],['b','b','b'],['c','c','c']]
the_list[0][2] = 'hi'
the_list[1][2] = 'hi'
the_list[0][1] = 'hi'
Output:
the_list = [['a', 'hi', 'hi'], ['b', 'b', 'hi'], ['b', 'b', 'b'],['c', 'c', 'c']]
Please kindly recommend the better way of doing it
Thank you in advance
for i, j in indexA:
the_list[i][j] = 'hi'
print(the_list)
gives
[['a', 'hi', 'hi'], ['b', 'b', 'hi'], ['b', 'b', 'b'], ['c', 'c', 'c']]
you can try a parallel looping through your Index list to change the main list
for x,y in IndexA:
the_list[x][y] = "Hi"
The only way to change the value in the list is to change it manually as you did. The only thing you can do is use a For Loop instead of writing manually like below.
change_to = 'hi'
indexA = [(0,2),(1,2),(0,1)]
for i in indexA:
the_list[i[0]i[1]] = change_to
You have to manually refer to change the value. So improve it this way.
hope it helps

How to keep unique inner lists within a list of lists by ignoring one element of the inner list

I have a list of lists, and would like to keep the unique lists by ignoring one element of the list.
MWE:
my_list_of_lists = [['b','c','1','d'],['b','c','1','d'],['b','c','2','e']]
print(my_list_of_lists)
new_list_of_lists = []
for the_list in my_list_of_lists:
if the_list not in new_list_of_lists:
new_list_of_lists.append(the_list)
print(new_list_of_lists)
MWE Output:
[['b', 'c', '1', 'd'], ['b', 'c', '1', 'd'], ['b', 'c', '2', 'e']] # 1st print
[['b', 'c', '1', 'd'], ['b', 'c', '2', 'e']] # 2nd print
Question:
Is there a Pythonic way to remove duplicates as with the example above by ignoring a specific element within the inner list?
ie for my_list_of_lists = [['b','c','1','d'],['b','c','3','d'],['b','c','2','e']] should yield [['b','c','1','d'],['b','c','2','e']]
my_list_of_lists = [['b','c','1','d'],['b','c','3','d'],['b','c','2','e']]
# my_list_of_lists[0] and my_list_of_lists[1] are identical
# if my_list_of_lists[n][-2] is ignored
print(my_list_of_lists)
new_list_of_lists = []
for the_list in my_list_of_lists:
if the_list[ignore:-2] not in new_list_of_lists: #ignore the second last element when comparing
new_list_of_lists.append(the_list)
print(new_list_of_lists)
This is not "Pythonic" per se, but it is relatively short and gets the job done:
my_list_of_lists = [['b','c','1','d'],['b','c','3','d'],['b','c','2','e']]
print(my_list_of_lists)
new_list_of_lists = []
ignore = 2
for the_list in my_list_of_lists:
if all(
any(e != other_list[i]
for i, e in enumerate(the_list)
if i != ignore)
for other_list in new_list_of_lists
):
new_list_of_lists.append(the_list)
print(new_list_of_lists)
It outputs [['b', 'c', '1', 'd'], ['b', 'c', '2', 'e']] for the given input.
My question and your reply from the comments:
"ignoring a specific element" - Which one? The first? The largest? The one that's a digit? Some other rule? Your example input doesn't specify. – Heap Overflow
#HeapOverflow, I think a generic (non-specific) function would be best as other users in the future can integrate this generic function for their own use. – 3kstc
Doing that #GreenCloakGuy's style:
def unique(values, key):
return list({key(value): value for value in values}.values())
new_list_of_lists = unique(my_list_of_lists, lambda a: tuple(a[:2] + a[3:]))
A bit shorter:
def unique(values, key):
return list(dict(zip(map(key, values), values)).values())
Those take the last duplicate. If you want the first, you could use this:
def unique(values, key):
tmp = {}
for value in values:
tmp.setdefault(key(value), value)
return list(tmp.values())
The following approach
Creates a dict
where the values are the lists in the list-of-lists
and the corresponding keys are those lists without the indices you want to ignore, converted to tuples (since lists cannot be used as dict keys but tuples can)
Gets the dict's values, which should appear in order of insertion
Converts that to a list, and returns it
This preserves the later elements in the original list, as they overwrite earlier elements that are 'identical'.
def filter_unique(list_of_lists, indices_to_ignore):
return list({
tuple(elem for idx, elem in enumerate(lst) if idx not in indices_to_ignore) : lst
for lst in list_of_lists
}.values())
mlol = [['b','c','1','d'],['b','c','3','d'],['b','c','2','d']]
print(filter_unique(mlol, [2]))
# [['b', 'c', '3', 'd'], ['b', 'c', '2', 'e']]
print(filter_unique(mlol, [3]))
# [['b', 'c', '1', 'd'], ['b', 'c', '3', 'd'], ['b', 'c', '2', 'e']]
That's a one-liner, abusing a dict comprehension. A multi-line version might look like this:
def filter_unique(list_of_lists, indices_to_ignore):
dct = {}
for lst in list_of_lists:
key = []
for idx, elem in enumerate(lst):
if idx not in indices_to_ignore:
key.append(elem)
dct[tuple(key)] = lst
return list(dct.values())

replace duplicate values in a list with 'x'?

I am trying to understand the process of creating a function that can replace duplicate strings in a list of strings. for example, I want to convert this list
mylist = ['a', 'b', 'b', 'a', 'c', 'a']
to this
mylist = ['a', 'b', 'x', 'x', 'c', 'x']
initially, I know I need create my function and iterate through the list
def replace(foo):
newlist= []
for i in foo:
if foo[i] == foo[i+1]:
foo[i].replace('x')
return foo
However, I know there are two problems with this. the first is that I get an error stating
list indices must be integers or slices, not str
so I believe I should instead be operating on the range of this list, but I'm not sure how to implement it. The other being that this would only help me if the duplicate letter comes directly after my iteration (i).
Unfortunately, that's as far as my understanding of the problem reaches. If anyone can provide some clarification on this procedure for me, I would be very grateful.
Go through the list, and keep track of what you've seen in a set. Replace things you've seen before in the list with 'x':
mylist = ['a', 'b', 'b', 'a', 'c', 'a']
seen = set()
for i, e in enumerate(mylist):
if e in seen:
mylist[i] = 'x'
else:
seen.add(e)
print(mylist)
# ['a', 'b', 'x', 'x', 'c', 'x']
Simple Solution.
my_list = ['a', 'b', 'b', 'a', 'c', 'a']
new_list = []
for i in range(len(my_list)):
if my_list[i] in new_list:
new_list.append('x')
else:
new_list.append(my_list[i])
print(my_list)
print(new_list)
# output
#['a', 'b', 'b', 'a', 'c', 'a']
#['a', 'b', 'x', 'x', 'c', 'x']
The other solutions use indexing, which isn't necessarily required.
Really simply, you could check if the value is in the new list, else you can append x. If you wanted to use a function:
old = ['a', 'b', 'b', 'a', 'c']
def replace_dupes_with_x(l):
tmp = list()
for char in l:
if char in tmp:
tmp.append('x')
else:
tmp.append(char)
return tmp
new = replace_dupes_with_x(old)
You can use the following solution:
from collections import defaultdict
mylist = ['a', 'b', 'b', 'a', 'c', 'a']
ret, appear = [], defaultdict(int)
for c in mylist:
appear[c] += 1
ret.append(c if appear[c] == 1 else 'x')
Which will give you:
['a', 'b', 'x', 'x', 'c', 'x']

Split words in string into nested lists of characters

Can anyone help me with a list comprehension to split a string into a nested list of words and characters? i.e:
mystring = "this is a string"
Wanted ouput:
[['t','h','i','s'],['i','s'],['a'],['s','t','r','i','n','g']]
I've tried the following, but it doesnt split 'x' into nested list:
mylist = [x.split() for x in mystring.split(' ')]
print(mylist)
[['this'],['is'],['a'],['string']]
[list(x) for x in mystring.split(' ')]
You can use a nested list comprehension:
[[j for j in i] for i in mystring.split()]
Yields:
[['t', 'h', 'i', 's'], ['i', 's'], ['a'], ['s', 't', 'r', 'i', 'n', 'g']]
You need list(x) instead of x.split():
[list(x) for x in mystring.split()]
Slightly similar to other answers
map(list,mystring.split(" "))

Removing a string from a list inside a list of lists

What I'm trying to achieve here in a small local test is to iterate over an array of strings, which are basically arrays of strings inside a parent array.
I'm trying to achieve the following...
1) Get the first array in the parent array
2) Get the rest of the list without the one taken
3) Iterate through the taken array, so I take each of the strings
4) Look for each string taken in all of the rest of the arrays
5) If found, remove it from the array
So far I've tried the following, but I'm struggling with an error that I don't know where it does come from...
lines = map(lambda l: str.replace(l, "\n", ""),
list(open("PATH", 'r')))
splitLines = map(lambda l: l.split(','), lines)
for line in splitLines:
for keyword in line:
print(list(splitLines).remove(keyword))
But I'm getting the following error...
ValueError: list.remove(x): x not in list
Which isn't true as 'x' isn't a string included in any of the given test arrays.
SAMPLE INPUT (Comma separated lines in a text file, so I get an array of strings per line):
[['a', 'b', 'c'], ['e', 'f', 'g'], ['b', 'q', 'a']]
SAMPLE OUTPUT:
[['a', 'b', 'c'], ['e', 'f', 'g'], ['q']]
You can keep track of previously seen strings using a set for fast lookups, and using a simple list comprehension to add elements not found in the previously seen set.
prev = set()
final = []
for i in x:
final.append([j for j in i if j not in prev])
prev = prev.union(set(i))
print(final)
Output:
[['a', 'b', 'c'], ['e', 'f', 'g'], ['q']]
inputlist = [['a', 'b', 'c'], ['e', 'f', 'g'], ['b', 'q', 'a']]
scanned=[]
res=[]
for i in inputlist:
temp=[]
for j in i:
if j in scanned:
pass
else:
scanned.append(j)
temp.append(j)
res.append(temp)
[['a', 'b', 'c'], ['e', 'f', 'g'], ['q']]

Categories