This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 2 years ago.
I'm having trouble understanding how 'for loop' works in Python. I want to remove a character from a list using for loop to iterate through the list but the output is not as expected.
In the following code I want to remove the character 'e':
lista = ['g', 'e', 'e', 'k', 'e','s', 'e', 'e']
for x in lista:
if x == 'e':
lista.remove(x)
print(lista)
It prints ['g', 'k', 's', 'e', 'e'] when I was expecting ['g', 'k', 's'].
Thank you.
You cannot remove things from a list when you iterate over it. This is because when you remove an item from the list it shrinks. So what's happening is that when you encounter an 'e', the list is shrunk and you go to the next item in the list. But since the list shrunk, you're actually jumping over an item.
To solve your problem, you have to iterate over copy of your list.
lista = ['g', 'e', 'e', 'k', 'e','s', 'e', 'e']
for x in lista.copy():
if x == 'e':
lista.remove(x)
print(lista)
You can use the following code
lista = ['g', 'e', 'e', 'k', 'e','s', 'e', 'e']
for i in range(0, len(lista)):
element = lista[i]
if element == 'e':
del lista[i]
The above approach will modify the original list.
A far more simpler and better way is as follows:
list(filter(('e').__ne__, lista))
Both the methods return
['g', 'k', 's']
A solution to your problem may be this :
while 1:
try:
lista.remove("e")
except ValueError:
break
The simple list comprehension. The idea is to not update the list while iterating.
lista = ['g', 'e', 'e', 'k', 'e','s', 'e', 'e']
lista = [i for i in lista if i!='e']
I think the most pythonic way is to do it using list comprehension as shown below:
lista = ['g', 'e', 'e', 'k', 'e','s', 'e', 'e']
lista = [x for x in lista if x != 'e']
print(lista)
The reason why your method is not working is because you cannot remove items from a list whilst iterating over it, as you will be changing the indexes of each object in the list.
When you remove an item from a List it gets updated. Therefore shrinking it.
Thus, in your case when first two of the e's are removed, last two elements are not taken into consideration.
What you need to do is to check if the the element still exists-
lista = ['g', 'e', 'e', 'k', 'e', 's', 'e', 'e']
while 'e' in lista:
lista.remove('e')
print(lista)
UPDATE:
As #mad_ pointed out, you can reduce the complexity by-
lista = ['g', 'e', 'e', 'k', 'e', 's', 'e', 'e']
print([i for i in lista if i != 'e'])
Related
I have a list of lists and I want to remove duplicates within each nested list.
Input: [['c', 'p', 'p'], ['a', 'a', 'a'], ['t', 't', 'p']]
Output: [['c', 'p'], ['a'], ['t','p']]
The key here is that I cannot use the set() function or fromkeys().
Here is the code I have,
ans = []
for i in letters:
[ans.append([x]) for x in i if x not in ans]
which returns
[['c'], ['p'], ['p'], ['a'], ['a'], ['a'], ['t'], ['t'], ['p']]
which isn't what I want.
You tripped yourself up with the nested lists. A second loop is necessary to filter the elements. Although it's quite inefficient, you can write your attempt as
ans = []
for i in letters:
k = []
for j in i:
if j not in k:
k.append(j)
ans.append(k)
You can likely shorten this code, but not reduce its complexity.
To do that, you can use something sorted and itertools.groupby. this is still less efficient than a hash table, but better than linear lookup (although it likely doesn't matter much for short arrays):
ans = [[k for k, _ in groupby(sorted(i))] for i in letters]
You can iterate over the inner list and check if that character is already present or not
inputList = [['c', 'p', 'p'], ['a', 'a', 'a'], ['t', 't', 'p']]
result = []
for l in inputList:
# create a empty list to store intermediate result
tmp = []
# iterate over sublist
for ch in l:
if ch not in tmp: tmp.append(ch)
result.append(tmp)
print(result)
Since you can't use set() or fromkeys(), I would suggest a normal loop iteration, each time checking if value is already present:
lst = [['c', 'p', 'p'], ['a', 'a', 'a'], ['t', 't', 'p']]
new_lst = []
for x in lst:
res = []
for y in x:
if y not in res:
res.append(y)
new_lst.append(res)
print(new_lst)
Ideally, new_lst here should be a set.
list=[['c', 'p', 'p'], ['a', 'a', 'a'], ['t', 't', 'p']]
ans=[]
for sublist in list:
temp=[]
for ch in sublist:
if ch not in temp:
temp.append(ch)
ans.append(temp)
print(ans)
#I think it should work, very simple, it could be more complex
Just ignore every instance of a letter until it is the last one.
for every sublist of input:[[...] for sub in input]
store the letter if it isn't in the rest of the sublist:[ltr for i, ltr in enumerate(sub) if ltr not in sub[i+1:]]
Put it together and you have:
input = [['c', 'p', 'p'], ['a', 'a', 'a'], ['t', 't', 'p']]
output = [[ltr for i, ltr in enumerate(sub) if ltr not in sub[i+1:]] for sub in input]
print(output) #[['c', 'p'], ['a'], ['t', 'p']]
I an trying to select unique datasets from a very large quite inconsistent list.
My Dataset RawData consists of string-items of different length.
Some items occure many times, for example: ['a','b','x','15/30']
The key to compare the item is always the last string: for example '15/30'
The goal is: Get a list: UniqueData with items that occure only once. (i want to keep the order)
Dataset:
RawData = [['a','b','x','15/30'],['d','e','f','g','h','20/30'],['w','x','y','z','10/10'],['a','x','c','15/30'],['i','j','k','l','m','n','o','p','20/60'],['x','b','c','15/30']]
My desired solution Dataset:
UniqueData = [['a','b','x','15/30'],['d','e','f','g','h','20/30'],['w','x','y','z','10/10'],['i','j','k','l','m','n','o','p','20/60']]
I tried many possible solutions for instance:
for index, elem in enumerate(RawData): and appending to a new list if.....
for element in list does not work, because the items are not exactly the same.
Can you help me finding a solution to my problem?
Thanks!
The best way to remove duplicates is to add them into a set. Add the last element into a set as to keep track of all the unique values. When the value you want to add is already present in the set unique do nothing if not present add the value to set unique and append the lst to result list here it's new.
Try this.
new=[]
unique=set()
for lst in RawData:
if lst[-1] not in unique:
unique.add(lst[-1])
new.append(lst)
print(new)
#[['a', 'b', 'x', '15/30'],
['d', 'e', 'f', 'g', 'h', '20/30'],
['w', 'x', 'y', 'z', '10/10'],
['i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', '20/60']]
You could set up a new array for unique data and to track the items you have seen so far. Then as you loop through the data if you have not seen the last element in that list before then append it to unique data and add it to the seen list.
RawData = [['a', 'b', 'x', '15/30'], ['d', 'e', 'f', 'g', 'h', '20/30'], ['w', 'x', 'y', 'z', '10/10'],
['a', 'x', 'c', '15/30'], ['i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', '20/60'], ['x', 'b', 'c', '15/30']]
seen = []
UniqueData = []
for data in RawData:
if data[-1] not in seen:
UniqueData.append(data)
seen.append(data[-1])
print(UniqueData)
OUTPUT
[['a', 'b', 'x', '15/30'], ['d', 'e', 'f', 'g', 'h', '20/30'], ['w', 'x', 'y', 'z', '10/10'], ['i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', '20/60']]
RawData = [['a','b','x','15/30'],['d','e','f','g','h','20/30'],['w','x','y','z','10/10'],['a','x','c','15/30'],['i','j','k','l','m','n','o','p','20/60'],['x','b','c','15/30']]
seen = []
seen_indices = []
for _,i in enumerate(RawData):
# _ -> index
# i -> individual lists
if i[-1] not in seen:
seen.append(i[-1])
else:
seen_indices.append(_)
for index in sorted(seen_indices, reverse=True):
del RawData[index]
print (RawData)
Using a set to filter out entries for which the key has already been seen is the most efficient way to go.
Here's a one liner example using a list comprehension with internal side effects:
UniqueData = [rd for seen in [set()] for rd in RawData if not(rd[-1] in seen or seen.add(rd[-1])) ]
Hi I have a list as following:
listt = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o']
15 members.
I want to turn it into 3 lists, I used this code it worked but I want unique lists. this give me 3 lists that have mutual members.
import random
listt = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o']
print(random.sample(listt,5))
print(random.sample(listt,5))
print(random.sample(listt,5))
Try this:
from random import shuffle
def randomise():
listt = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o']
shuffle(listt)
return listt[:5], listt[5:10], listt[10:]
print(randomise())
This will print (for example, since it is random):
(['i', 'k', 'c', 'b', 'a'], ['d', 'j', 'h', 'n', 'f'], ['e', 'l', 'o', 'g', 'm'])
If it doesn't matter to you which items go in each list, then you're better off partitioning the list into thirds:
In [23]: L = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o']
In [24]: size = len(L)
In [25]: L[:size//3]
Out[25]: ['a', 'b', 'c', 'd', 'e']
In [26]: L[size//3:2*size//3]
Out[26]: ['f', 'g', 'h', 'i', 'j']
In [27]: L[2*size//3:]
Out[27]: ['k', 'l', 'm', 'n', 'o']
If you want them to have random elements from the original list, you'll just need to shuffle the input first:
random.shuffle(L)
Instead of sampling your list three times, which will always give you three independent results where individual members may be selected for more than a single list, you could just shuffle the list once and then split it in three parts. That way, you get three random subsets that will not share any items:
>>> random.shuffle(listt)
>>> list[0:5]
>>> listt[0:5]
['b', 'a', 'f', 'e', 'h']
>>> listt[5:10]
['c', 'm', 'g', 'j', 'o']
>>> listt[10:15]
['d', 'l', 'i', 'n', 'k']
Note that random.shuffle will shuffle the list in place, so the original list is modified. If you don’t want to modify the original list, you should make a copy first.
If your list is larger than the desired result set, then of course you can also sample your list once with the combined result size and then split the result accordingly:
>>> sample = random.sample(listt, 5 * 3)
>>> sample[0:5]
['h', 'm', 'i', 'k', 'd']
>>> sample[5:10]
['a', 'b', 'o', 'j', 'n']
>>> sample[10:15]
['c', 'l', 'f', 'e', 'g']
This solution will also avoid modifying the original list, so you will not need a copy if you want to keep it as it is.
Use [:] for slicing all members out of the list which basically copies everything into a new object. Alternatively just use list(<list>) which copies too:
print(random.sample(listt[:],5))
In case you want to shuffle only once, store the shuffle result into a variable and copy later:
output = random.sample(listt,5)
first = output[:]
second = output[:]
print(first is second, first is output) # False, False
and then the original list can be modified without the first or second being modified.
For nested lists you might want to use copy.deepcopy().
This question already has an answer here:
How can I group equivalent items together in a Python list?
(1 answer)
Closed 3 years ago.
I want to split a list sequence of items in Python or group them if they are similar.
I already found a solution but I would like to know if there is a better and more efficient way to do it (always up to learn more).
Here is the main goal
input = ['a','a', 'i', 'e', 'e', 'e', 'i', 'i', 'a', 'a']
desired_ouput = [['a','a'], ['i'], ['e','e', 'e'], ['i', 'i'], ['a', 'a']
So basically I choose to group by similar neighbour.I try to find a way to split them if different but get no success dooing it.
I'm also keen on listening the good way to expose the problem
#!/usr/bin/env python3
def group_seq(listA):
listA = [[n] for n in listA]
for i,l in enumerate(listA):
_curr = l
_prev = None
_next= None
if i+1 < len(listA):
_next = listA[i+1]
if i > 0:
_prev = listA[i-1]
if _next is not None and _curr[-1] == _next[0]:
listA[i].extend(_next)
listA.pop(i+1)
if _prev is not None and _curr[0] == _prev[0]:
listA[i].extend(_prev)
listA.pop(i-1)
return listA
listA = ['a','a', 'i', 'e', 'e', 'e', 'i', 'i', 'a', 'a']
output = group_seq(listA)
print(listA)
['a', 'a', 'i', 'e', 'e', 'e', 'i', 'i', 'a', 'a']
print(output)
[['a', 'a'], ['i'], ['e', 'e', 'e'], ['i', 'i'], ['a', 'a']]
I think itertool.groupby is probably the nicest way to do this. It's flexible and efficient enough that it's rarely to your advantage to re-implement it yourself:
from itertools import groupby
inp = ['a','a', 'i', 'e', 'e', 'e', 'i', 'i', 'a', 'a']
output = [list(g) for k,g in groupby(inp)]
print(output)
prints
[['a', 'a'], ['i'], ['e', 'e', 'e'], ['i', 'i'], ['a', 'a']]
If you do implement it yourself, it can probably be much simpler. Just keep track of the previous value and the current list you're appending to:
def group_seq(listA):
prev = None
cur = None
ret = []
for l in listA:
if l == prev: # assumes list doesn't contain None
cur.append(l)
else:
cur = [l]
ret.append(cur)
prev = l
return ret
I have a list of lists, and I want to return those sublists that have a specific char.
If the list is:
lst = [['a', 'e'], ['g', 'j'], ['m', 'n', 'w'], ['z']]
I want to retrive ['g', 'j'] "or it's position" if I search using j or g
Try this:-
lst = [['a', 'e'], ['g', 'j'], ['m', 'n', 'w'], ['z']]
def search(search_char):
result = [x for x in lst if search_char in x]
return result
print(search('g'))
For a start there is a keyword error in your variable - list is a keyword, try my_list.
This works for returning the list you want:
#Try this
my_list = [['a', 'e'], ['g', 'j'], ['m', 'n', 'w'], ['z']]
def check_for_letter(a_list,search):
for i in a_list[:]:
if search in a_list[0]:
return a_list[0]
else:
a_list[0] = a_list[1]
Session below:
>>> check_for_letter(my_list,"j")
['g', 'j']
>>>
This is one way. It works even for repeats.
lst = [['a', 'e'], ['g', 'j'], ['m', 'n', 'w'], ['z']]
def searcher(lst, x):
for i in range(len(lst)):
if x in lst[i]:
yield i
list(searcher(lst, 'g')) # [1]
list(map(lst.__getitem__, searcher(lst, 'g'))) # [['g', 'j']]
lst = [['a', 'e'], ['g', 'j'], ['m', 'n', 'w'], ['z']]
spec_char = input("What character do you want to find?: ")#ask for a character to find
def find_char(spec_char):
for list_count, each_list in enumerate(lst): #iterates through each list in lst
if spec_char in each_list: #checks if specified character is in each_list
return spec_char, lst[list_count] #returns both the character and list that contains the character
def main(): #good habit for organisation
print(find_char(spec_char)) #print the returned value of find_char
if __name__ == '__main__':
main()
lst = [['a', 'e'], ['g', 'j'], ['m', 'n', 'w'], ['z']]
def search(spec_char):
for subList in lst:
if spec_char in subList:
return subList
return False
print search('g')
>>> ['g', 'j']
y=[['a','b'],['c','d'],['e','f'],['f']]
result=[x for x in y if 'f' in x])
here I took 'f' as the character to be searched
Alternatively, we can also use the lambda and the filter functions.
The basics for lambda and filter function can be found in python documentation.
lst = [['a', 'e'], ['g', 'j'], ['m', 'n', 'w'], ['z']]
ch = input('Enter the character') # or directly type the character in ''
# lambda <parameter to the function>: <value to be returned>
# filter(<lambda function to check for the condition>, <sequence to iterate over>)
r = list(filter(lambda lst: ch in lst,lst))
print(r)
Note: To see the value returned by the lambda and the filter functions, I am storing the result in a list and printing the final output.
Below is the solution and explanation for your question. Please view the image at the bottom of this answer for further clarification and to view the output.
lst = [['a', 'e'], ['g', 'j'], ['m', 'n', 'w'], ['z']] #So this is your list
character=input("Enter the character: ") #The character you are searching for
for a in lst: #it means that variable [a] is an item in the list [lst]
for b in a: #it means that variable [b] is an item in the list [a]
if(b==character): #To check if the given character is present in the list
print(a) #Finally to print the list in which the given character is present
So, the code part is over. Now, let's look what the output will be.
C:\Users\User\Desktop\python>coc.py
Enter the character: a
['a', 'e']
C:\Users\User\Desktop\python>coc.py
Enter the character: w
['m', 'n', 'w']
Click here to view the image of my code and output