How to .remove all matches in a Python list? [duplicate] - python

This question already has answers here:
Remove all occurrences of a value from a list?
(26 answers)
Closed 9 years ago.
If I have a bit of Python like:
n = [1, 3, 5, 1]
n.remove(1)
print n
n will return [3, 5, 1] because .remove() quits after it finds its first match. What could I do to return just [3, 5], having found all matches (or in this case, all the 1s)?

If creating a new list is fine:
n = [x for x in n if x != 1]
Of course you could also use slice assignment to modify the list in place:
n[:] = [x for x in n if x != 1]

use filter function
n = [1, 3, 5, 1]
filter(lambda a:a is not 1,n)
[3,5]
edit
n = [1, 3, 5, 1]
filter(lambda a:a != 1,n)
[3,5]

Simple List Comprehension -
>>> n = [1, 3, 5, 1]
>>> n = [e for e in n if e != 1]
>>> n
[3, 5]
If you wanted to remove more than one elements -
>>> g = [1,3]
>>> n = [e for e in n if e not in g]
>>> n
[5]

This is not how I'd normally do this, but:
n = [1, 3, 5, 1]
REMOVECHAR = 1
while REMOVECHAR in n:
n.remove(REMOVECHAR)
# could also do:
# while 1:
# try: n.remove(REMOVECHAR)
# except ValueError as e: break
If I were doing it, I would use a list comp to make a new list.
n = [1,3,5,1]
REMOVECHAR = 1
nn = [element for element in n if element != REMOVECHAR]

You could iterate backwards through the list and pop elements that match.
def remove_all_in_place(target, sequence):
cursor = len(target) - 1
while cursor >= 0:
if sequence[cursor] == target:
sequence.pop(cursor)
cursor -= 1
List comprehensions might be faster since they are optimized, but they aren't in-place operations. For native Python implementations, I think this would be fastest, as well as being true in-place.

Related

Unable to reset counters in for loop

I am trying to amend a list of integers in a way that every 2 duplicating integers will be multiplied by 2 and will replace the duplicates. here is an example:
a = [1, 1, 2, 3] = [2, 2 ,3] = [4 ,3]
also : b = [2, 3, 3, 6 ,9] = [2 , 6 , 6, 9] = [2, 12 , 9]
I am using the code below to achieve this. Unfortunately, every time I find a match my index would skip the next match.
user_input = [int(a) for a in input().split()]
for index, item in enumerate(user_input):
while len(user_input)-2 >= index:
if item == user_input[index + 1]:
del user_input[index]
del user_input[index]
item += item
user_input.insert(index,item)
break
print(*user_input)
In Python, you should never modify a container object while you are iterating over it. There are some exceptions if you know what you are doing, but you certainly should not change the size of the container object. That is what you are trying to do and that is why it fails.
Instead, use a different approach. Iterate over the list but construct a new list. Modify that new list as needed. Here is code that does what you want. This builds a new list named new_list and either changes the last item(s) in that list or appends a new item. The original list is never changed.
user_input = [int(a) for a in input().split()]
new_list = []
for item in user_input:
while new_list and (item == new_list[-1]):
new_list.pop()
item *= 2
new_list.append(item)
print(*new_list)
This code passes the two examples you gave. It also passes the example [8, 4, 2, 1, 1, 7] which should result in [16, 7]. My previous version did not pass that last test but this new version does.
Check if this works Rory!
import copy
user_input = [1,1,2,3]
res = []
while res!=user_input:
a = user_input.pop(0)
if len(user_input)!=0
b = user_input.pop(0)
if a==b:
user_input.insert(0,a+b)
else:
res.append(a)
user_input.insert(0,b)
else:
res.append(a)
user_input = copy.deepcopy(res)
You can use itertools.groupby and a recursion:
Check for same consecutive elements:
def same_consec(lst):
return any(len(list(g)) > 1 for _, g in groupby(lst))
Replace consecutive same elements:
def replace_consec(lst):
if same_consec(lst):
lst = [k * 2 if len(list(g)) > 1 else k for k, g in groupby(lst)]
return replace_consec(lst)
else:
return lst
Usage:
>>> a = [8, 4, 2, 1, 1, 7]
>>> replace_consec(a)
[16, 7]

How to store indeces of the respective numbers in a list in seperate array using Python

I am using python 3.6.This program should store the value of indexes of the numbers of one array into another (index starting with 1) For Eg if array is [2,3,1] the next one should be [3,1,2].. but while implemending the list gets changed.
I tried to do with respect to values of 1st array but no use it gets changed when doing the logic.
n = int(input())
arr = input()
l = list(map(int,arr.split(' ')))
arr1= l
print(l)
for i in range(0,n):
print(l[i])
arr1[l[i]-1]=i+1
print(arr1)
Answer should be [4,1,2,3] but answer is [2,1,4,3]
enter code here
You are asking for an array of the indexes of the numbers, but your example shows the indexes +1. It would probably be cleaner to stick with zero indexing.
Nevertheless, if you're looking for a (somewhat) flexible approach, you could do something like this with a list comprehension:
>>> l = [2, 3, 1]
>>> [l.index(i+1) +1 if i+1 in l else None for i in range(max(l))]
[3, 1, 2]
Given an array that's spread out, it will fill with None:
>>> l = [2, 3, 7, 1]
>>> [l.index(i+1) +1 if i+1 in l else None for i in range(max(l))]
[4, 1, 2, None, None, None, 3]
It will silently ignore dupes:
>>> l = [2, 2, 1, 2]
>>> [l.index(i+1) +1 if i+1 in l else None for i in range(max(l))]
[3, 1]
you can do it this way:
x = [2, 3, 1]
ind = [x.index(e) for e in sorted(x)]
# if you want your indices to start from 1
[e+1 for e in ind]

Slicing list the other way around?

I have this list:
arr = [1, 2, 3, 4, 5, 6]
What I wanted to do is make a new list with values from index 5 to index 1.
Output would be:
[6, 1, 2]
This is what I've done:
output = arr[5:] + arr[:2]
But I wanted to know if there's another way of slicing it.
Like just a normal slicing like for example:
output = arr[5:1]
But I know it's not gonna work because I've done that. Could you please help me?
As far as I'm aware, doing this without writing your own custom code doesn't seem possible. Python doesn't wrap lists around.
You can create a custom generator to do what you want, though:
>>> def cycle(l, start=0):
... l = l[start:] + l[:start]
... while True:
... x = l.pop(0)
... yield x
... l.append(x)
...
>>> k = cycle(a, 5)
>>> next(k)
6
>>> next(k)
1
>>> next(k)
2
(Example rolled back due to OP's post change.)
Here's an improved version that will take into account the number elements you want to get from the generator:
>>> def cycle(l, start=0, iters=None):
... l = l[start:] + l[:start]
... i = 0
... while True:
... if iters is not None and i == iters:
... raise StopIteration
... x = l.pop(0)
... yield x
... l.append(x)
... i += 1
...
>>> a = [1, 2, 3, 4, 5, 6]
>>> list(cycle(a, start=5, iters=3))
[6, 1, 2]
Update:
Rotate left n elements (or right for negative n) and slice number of element you want
L = L[n:] + L[:n] # rotate left n elements
In ur case n is 5:
>>> output = arr[5:] + arr[:5]
>>> output[:3]
[6, 1, 2]
Previous
>>> arr = [1, 2, 3, 4, 5, 6]
>>> output = arr[:]
>>> del output[2:5]
>>> output
[1, 2, 6]
>>>
Create a function to slice the input array for you and append the two parts together to get the desired list.
def cyc_slice(lst, start, n):
return lst[start:] + lst[:(start+n)%len(lst)]
Unlike both other answers, this doesn't make a superflous copy of all the list elements that you don't want.
>>> arr=[1,2,3,4,5,6]
>>> cyc_slice(arr, 5, 3)
[6, 1, 2]
And an improved iterator solution:
def cycle(l, start=0, n=None):
if not l:
return
idx = start-1
end = (idx + n) % len(l) if n else -1
while idx != end:
idx+=1
try:
x = l[idx]
except IndexError:
idx = 0
x = l[idx]
yield x
when provided with a count, it will provide that many elements. Otherwise, it can keep looping. This iterates through the list in place, so doesn't allocate any elements to memory (unless you create a list from it)
>>> list(cycle(arr,5,3))
[6, 1, 2]

How to set output as a list without space?

n is an integer and xs is a list of integers.
n = 2
xs = [1, 2, 3, 4, 5, 6]
def multiples(n,xs):
empty = []
for i in range(len(xs)):
if xs[i] % n == 0:
print(xs[i])
return empty
It should give me the output of 2, 4, 6 in three separate lines. Is any way I can merge them into a list that without space and only commas?
n=3
xs=[11, 13]
Will the output become '[]', the empty set?
You can just change your for loop to this:
print(",".join(str(x) for x in xs if not x % n))
A generator expression that does it all. I am assuming that your return empty line is just indented incorrectly because at that indentation, it would print only the first one.
You have a couple of problems in your code. The first problem is that you are only checking the first element in your array, and then you are returning out of your function. So, you are never actually completing iterating over your entire list.
Second, you are simply printing your items out, and per your requirements, and based on the fact that you created a list called empty, you want to collect this data and output it when you are finished.
With that being said, what you want to do instead is change your print statement to append to your list:
empty.append(xs[i])
Then when you are finished your for loop return empty.
Like this:
def multiples(n,xs):
empty = []
for i in range(len(xs)):
if xs[i] % n == 0:
empty.append(xs[i])
return empty
Use a list comprehension:
n = 2
xs = [1, 2, 3, 4, 5, 6, 7]
>>> [x for i, x in enumerate(xs, 1) if not i % n]
[2, 4, 6]
xs = [2, 3, 4, 5, 6, 7]
>>> [x for i, x in enumerate(xs, 1) if not i % n]
[3, 5, 7]
n = 3
xs = [11, 13]
>>> [x for i, x in enumerate(xs, 1) if not i % n]
[]
This results in a list of integers instead of strings.
As you want to take every n'th item from your list, you need to use enumerate (starting with a value of 1). The if xs[i] %n == 0 solution just happened to work because the list a continuous range. Try xs = [3, 3, 3, 3] and see what happens with your function and the other solutions...
To help understand what is going on, here is a table of the interim values.
i x i % 2 not i % 2
== == ===== =========
1 3 1 False
2 3 0 True
3 3 1 False
4 3 0 True

Python: Searching for an int in a list

Say I have this list
x = [1,2,3,1,5,1,8]
Is there a way to find every index that 1 is in the list?
Sure. A list comprehension plus enumerate should work:
[i for i, z in enumerate(x) if z == 1]
And the proof:
>>> x = [1, 2, 3, 1, 5, 1, 8]
>>> [i for i, z in enumerate(x) if z == 1]
[0, 3, 5]
The questioner asked for a solution using list.index, so here is one such solution:
def ones(x):
matches = []
pos = 0
while True:
try:
pos = x.index(1, pos)
except ValueError:
break
matches.append(pos)
pos += 1
return matches
It is somewhat more verbose than mgilson's solution, which I would consider to be more idiomatic Python.

Categories

Resources