Python - How to remove similar elements from a list? - python

For example I have a list:
L = [1, 2, 2, 3, 1, 1, 6, 10, 1, 3]
And I want to remove all 1's from the list, so that I would get:
L = [2, 2, 3, 6, 10, 3]
I tried iterating over the list and then deleting the element if it equals the element I want to delete (1 in this case), but turns out you can't iterate and delete stuff from a list at the same time since it messes up the counting. The best thing I've come up with is just construct a new list L2 that doesn't contain any of the 1's and then put that into L, but is there a solution that only involves mutating L?

but is there a solution that only involves mutating L?
You can rather iterate over a copy of your List - L[:], and remove element from L. That won't mess up counting.
If you really don't want to create a new list, you would have to iterate in reverse using range(len(L) - 1, -1, -1), but that won't be 'Pythonic' anymore.
>>> for x in L[:]:
... if x == 1:
... L.remove(x)
...
>>> L
[2, 2, 3, 6, 10, 3]
However, you can also use List Comprehension:
>>> L = [1, 2, 2, 3, 1, 1, 6, 10, 1, 3]
>>> L[:] = [x for x in L if x != 1]
>>> L
[2, 2, 3, 6, 10, 3]

Using the filter built-in:
>>> L = [1, 2, 2, 3, 1, 1, 6, 10, 1, 3]
>>> filter(lambda x: x is not 1, L)
[2, 2, 3, 6, 10, 3]
Or you can assign it back to L:
>>> L = [1, 2, 2, 3, 1, 1, 6, 10, 1, 3]
>>> L = filter(lambda x: x is not 1, L)
>>> L
[2, 2, 3, 6, 10, 3]
You can also wrap this concept into methods, to be able to specify a list of items to include/exclude:
def exclude(collection, exclude_list):
return filter(lambda x: x not in exclude_list, collection)
def include(collection, include_list):
return filter(lambda x: x in include_list, collection)
>>> L = [1, 2, 2, 3, 1, 1, 6, 10, 1, 3]
>>> L = exclude(L, [1])
>>> L
[2, 2, 3, 6, 10, 3]

If you don't want to mutate the list or generate any new copy of it. You can loop from end to begin and use index:
>>> for i in range(len(L)-1, -1, -1):
... if L[i] == 1:
... del L[i]

This is awkward to do in python without making a copy of the list...
This will do it without making a copy.
a = range(6) # Some array [0,1,2,3,4,5]
i=0
while i < len(a):
if a[i] == 4:
del a[i]
else:
i += 1
OUTPUT
>>> a
[0, 1, 2, 3, 5]

Related

How to create a list that represent the number of times a given item was shown?

This problem seems really stupid bu I can't get my head around it.
I have the following list:
a = [2, 1, 3, 1, 1, 2, 3, 2, 3]
I have to produce a second list which have the same size as the previous one but the values that appear should be the amount of times that a value showed up in the array until that point. For example:
b = [1, 1, 1, 2, 3, 2, 2, 3, 3]
So b[0] = 1 because it's the first time the item '2' appear on the 'a' list. b[5] = 2 and b[7] = 3 because it's the second and third time that the item '2' appear on the list 'a'.
Here a solution:
from collections import defaultdict
a = [2, 1, 3, 1, 1, 2, 3, 2, 3]
b = []
d = defaultdict(int)
for x in a:
d[x] +=1
b.append(d[x])
print(b)
Output:
[1, 1, 1, 2, 3, 2, 2, 3, 3]
I think using dictionary might help you, basically I am iterating the list and storing the current frequency of the number.
a = [2, 1, 3, 1, 1, 2, 3, 2, 3]
d = {}
z = []
for i in a:
if i not in d:
d[i] = 1
z.append(1)
else:
d[i]+=1
z.append(d[i])
print(z)
output = [1, 1, 1, 2, 3, 2, 2, 3, 3]

Swap two values randomly in list

I have the following list:
a = [1, 2, 5, 4, 3, 6]
And I want to know how I can swap any two values at a time randomly within a list regardless of position within the list. Below are a few example outputs on what I'm thinking about:
[1, 4, 5, 2, 3, 6]
[6, 2, 3, 4, 5, 1]
[1, 6, 5, 4, 3, 2]
[1, 3, 5, 4, 2, 6]
Is there a way to do this in Python 2.7? My current code is like this:
import random
n = len(a)
if n:
i = random.randint(0,n-1)
j = random.randint(0,n-1)
a[i] += a[j]
a[j] = a[i] - a[j]
a[i] -= a[j]
The issue with the code I currently have, however, is that it starts setting all values to zero given enough swaps and iterations, which I do not want; I want the values to stay the same in the array, but do something like 2opt and only switch around two with each swap.
You are over-complicating it, it seems. Just randomly sample two indices from the list, then swap the values at those indicies:
>>> def swap_random(seq):
... idx = range(len(seq))
... i1, i2 = random.sample(idx, 2)
... seq[i1], seq[i2] = seq[i2], seq[i1]
...
>>> a
[1, 2, 5, 4, 3, 6]
>>> swap_random(a)
>>> a
[1, 2, 3, 4, 5, 6]
>>> swap_random(a)
>>> a
[1, 2, 6, 4, 5, 3]
>>> swap_random(a)
>>> a
[1, 2, 6, 5, 4, 3]
>>> swap_random(a)
>>> a
[6, 2, 1, 5, 4, 3]
Note, I used the Python swap idiom, which doesn't require an intermediate variable. It is equivalent to:
temp = seq[i1]
seq[i1] = seq[i2]
seq[i2] = temp

How to change numbers around in a list (python)

i have been working on this for 3 hours now but i have no clue how to do it
can anyone help me with this?
values = [1, 2, 3, 4, 5]
temp = values[0]
for index in range (len(values) -1):
values[index] = values [index]
values[len(values)-1] = temp
print values
i want the printed values to be in order as [2,3,4,5,1]
by simply changing those in the brackets
deque is more efficient way to do
In [1]: import collections
In [3]: dq = collections.deque([1,2,3,4,5])
In [4]: dq.rotate(-1)
In [5]: dq
Out[5]: deque([2, 3, 4, 5, 1])
What you are trying to achieve is not available in the python libraries but you can leverage slicing to rotate list
Implementation
def rotate(seq, n = 1, direc = 'l'):
if direc.lower() == 'l':
seq = seq[n:] + seq[0:n]
else:
seq = seq[-n:] + seq[:-n]
return seq
Demonstration
>>> rotate(values)
[2, 3, 4, 5, 1]
>>> rotate(values,2,'l')
[3, 4, 5, 1, 2]
>>> rotate(values,2,'r')
[4, 5, 1, 2, 3]
Simple but powerful slice syntax:
values = [1, 2, 3, 4, 5]
shifted = values[1:]+values[:1]
assert shifted == [2, 3, 4, 5, 1]
How about time one-liner, in the spirit of sleepsort:
while values != [2, 3, 4, 5, 1]: random.shuffle(values)

Python : Generating cyclic permutations code (An unexpected code error to be clarified)

I didn't manage to correct a code I thought it would work for sure. Any advice to make the code functional is accepted.
Expected outputs of the following code is a list containing a cyclic permuation of the list
l = [1,2,3,4] (i.e : [[4, 1, 2, 3],[3, 4, 1, 2],[2, 3, 4, 1],[1, 2, 3, 4]])
Although what I get is : [[2, 3, 4, 1]]
The code :
def cycGen(l):
L=[]
while not(l in L) :
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
print(cycGen([1,2,3,4]))
Another variation of the solution is to consider the following code wich seems unfortunatly not working either :
def cycGen(l):
L=[]
for k in range(len(l)):
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
Help me with your generous knowlege sharing please.
You can use collections.deque:
from collections import deque
a = [1, 2, 3, 4]
d = deque(a)
for _ in range(len(a)):
d.rotate()
print(list(d))
Which gives you the output:
[4, 1, 2, 3]
[3, 4, 1, 2]
[2, 3, 4, 1]
[1, 2, 3, 4]
As mentioned in Efficient way to shift a list in python
An easy way is just:
In [12]: x = [1,2,3,4]
In [13]: [x[i:]+x[:i] for i in range(len(x))]
Out[13]: [[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
In your first code sample, the line L.append(l) appends a "reference" (loosely speaking) to the list l to the end of L, rather than appending a copy as you seem to be expecting. Thus, when l is later modified, the reference to it contained in L is modified as well, and so when l in L is tested, l will equal the reference to itself in L, and so the loop will end. The same basic problem causes your second code sample to return multiples of the same list rather than several different lists.
To store a copy of l at the current point in time in L instead, use L.append(l[:]).
Here is an easy way:
>>> def cycGen(l):
size = len(l)
return [[l[(i+j)%size] for i in range(size)] for j in range(size)]
>>> l = [1,2,3,4]
>>> print cycGen(l)
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
You could do this using a generator too:
a = [1, 2, 3, 4]
def next_pos(max):
i = 0
while True:
for n in xrange(max):
yield n + i
i += 1
pos = next_pos(len(a))
b = []
for i in xrange(len(a)):
n = []
for j in xrange(len(a)):
m = pos.next()
if m >= len(a):
m -= len(a)
n.append(a[m])
b.append(n)
print b
output:
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]

Duplicate each member in a list [duplicate]

This question already has answers here:
Repeating elements of a list n times
(14 answers)
Closed 5 months ago.
I want to write a function that reads a list [1,5,3,6,...]
and gives [1,1,5,5,3,3,6,6,...].
Any idea how to do it?
>>> a = range(10)
>>> [val for val in a for _ in (0, 1)]
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]
N.B. _ is traditionally used as a placeholder variable name where you do not want to do anything with the contents of the variable. In this case it is just used to generate two values for every time round the outer loop.
To turn this from a list into a generator replace the square brackets with round brackets.
>>> a = [1, 2, 3]
>>> b = []
>>> for i in a:
b.extend([i, i])
>>> b
[1, 1, 2, 2, 3, 3]
or
>>> [a[i//2] for i in range(len(a)*2)]
[1, 1, 2, 2, 3, 3]
numpy.repeat does what you want:
import numpy as np
yourList = [1,5,3,6]
n = 2
list(np.repeat(yourList, n))
result:
[1, 1, 5, 5, 3, 3, 6, 6]
If you don't mind using numpy arrays you can also omit the list() call in the last line.
If you already have the roundrobin recipe described in the documentation for itertools—and it is quite handy—then you can just use
roundrobin(my_list, my_list)
I would use zip and itertools.chain.
>>> import itertools
>>> l = [1,5,3,6,16]
>>> list(itertools.chain(*zip(l,l)))
[1, 1, 5, 5, 3, 3, 6, 6, 16, 16]
Note: I only used list to consume the generator to make it fit for printing. You probably don't need the list call in your code...
It is possible use list multiplication. Case you need each list member together just use sorted method.
>>> lst = [1,2,3,4]
>>> sorted(lst*2)
[1,1,2,2,3,3,4,4]
With a little slicing...
>>> a = [3, 1, 4, 1, 5]
>>> a[:0] = a[::2] = a[1::2] = a[:]
>>> a
[3, 3, 1, 1, 4, 4, 1, 1, 5, 5]
I would use
import itertools
foo = [1, 5, 3, 6]
new = itertools.chain.from_iterable([item, item] for item in foo)
new will be an iterator that lazily iterates over the duplicated items. If you need the actual list computed, you can do list(new) or use one of the other solutions.
One can use zip and flat the list
a = [3, 1, 4, 1, 5]
sum(zip(a,a), ()) # (3, 3, 1, 1, 4, 4, 1, 1, 5, 5)
The output is a tuple, but conversion to a list is easy.
Regarding flatting a tuple with sum see https://stackoverflow.com/a/952946/11769765 and python: flat zip.
For as much as Guido dislikes the functional operators, they can be pretty darned handy:
>>> from operator import add
>>> a = range(10)
>>> b = reduce(add, [(x,x) for x in a])
For a more general approach you could go with a list comprehension and a factor term.
Example
sample_list = [1,2,3,4,5]
factor = 2
new_list = [entry for entry in sample_list for _ in range(factor)]
Out:
>>> new_list
[1, 1, 2, 2, 3, 3, 4, 4, 5, 5]
Changing the factor variable will change how many entry of each item in the list you will have in the new list.
You could also wrap it up in a function:
def multiply_list_entries(list_, factor = 1):
list_multiplied = [entry for entry in list_ for _ in range(factor)]
return list_multiplied
>>> multiply_list_entries(sample_list, factor = 3)
[1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5]
ls1=[1,2,3]
ls2=[]
for i in ls1:
ls2.append(i)
ls2.append(i)
This code duplicates each elements in ls1
the result ls2 --> [1,1,2,2,3,3]

Categories

Resources