List count method in if condition of python - python

The following code doesn't work properly, I want it to make a list to a new list with no element appears more than twice. For instance, modify l = [3, 3, 3, 5, 9] to [3, 3, 5, 9]. Here is my code:
l = [3, 3, 3, 5, 9]
bl = []
for i in l:
if l.count(i) > 2:
l.remove(i)
else:
bl.append(i)
print(l)
print(bl)
Its output:
[3, 3, 5, 9]
[3, 5, 9]
The list l is correctly modified while the new list bl is not as I expected. I think it's wrong at my if-statement.

You are modifiyint your list while iterating over it, create a copy to solve it:
l = [3,3,3,5,9]
bl = []
for i in l[::]:
if l.count(i) > 2:
l.remove(i)
else:
bl.append(i)
print(l)
print(bl)
Here you have a live example

I think you should not care about how many times the current element is in the source list, but if it's already two times in the target list or not:
l = [3,3,3,5,9]
bl = []
for i in l:
if bl.count(i) < 2:
bl.append(i)
print(l)
print(bl)
#[3, 3, 3, 5, 9]
#[3, 3, 5, 9]

Using collections.Counter
from collections import Counter
l = [3,3,3,5,9]
c = Counter(l)
l_new = [k for k,v in c.items() for _ in range(min(v,2))]
#[3, 3, 5, 9]
Note that by using count() for each element in the list you end up with a O(n**2) solution for something that can be done in linear time.
This is why I'm using a counter here.

Related

Python: Replace duplicate values in a list with the same values

I have a list and would like to convert all duplicates values to 3 without changing the order and without importing any packages
X = [1, 2, 2, 5, 4, 8, 6]
Desired output:
X = [1, 3, 3, 5, 4, 8, 6]
This code automatically replace all duplicate items with 3
my_list = [1, 2, 2, 5, 4, 8, 6]
new = []
for item in my_list:
if my_list.count(item) > 1:
new.append(3)
else:
new.append(item)
print(new)
Among the fastest
fr = {x:0 for x in X}
for n in X:
fr[n] += 1
Y = [3 if fr[n]>1 else n for n in X]
You iterate over the list and add one to the dictionary counter for that number.
Then you create a list with list comprehension: you change the value to 3 if it is repeated more than once.
Little bit slower and little bit shorter
xi = {x:i for i, x in enumerate(X)}
dp = {x: xi[x]>i for i, x in reversed(list(enumerate(X)))}
Y = [3 if dp[x] else x for x in X]
You iterate over X and keep the lastest index of each value. Then you iterate again but in reverse order, and ask if there is another index for that value. Then with that info you create the desired output. All using list/dict comprehension. This is more of a functional approach.
Not sure why another user deleted their answer but that was a pretty simple one and uses basic list comprehension. So I am bringing the same to you. Please refer the code below for same:
X = [1, 2, 2, 5, 4, 8, 6]
print([3 if e==2 else e for e in X])
You should be able to use a for loop for this
my_list = [1, 2, 2, 5, 4, 8, 6]
new_list = []
for i in range(len(my_list)):
if my_list[i] in new_list:
new_list.append(3)
else:
new_list.append(my_list[i])
print(new_list)
Output:
[1, 3, 3, 5, 4, 8, 6]
Maybe something like this:
X = [t if t not in X[:i] + X[i+1:] else 3 for i, t in enumerate(X)]

Remove specific words within a list with over twice occurance python

Here is a list A=[1,1,1,2,2,2,4,5,6,6,7,7,7]
Can we have an algorithm that modifies all the numbers that occur more than twice to be maximized twice in list A?
e.g. list new_A=[1,1,2,2,4,5,6,6,7,7]
I have tried the conditions to separate:
if Counter(list A)[num]>2:```
You can use groupby and islice:
from itertools import groupby, islice
lst = [1,1,1,2,2,2,4,5,6,6,7,7,7]
output = [x for _, g in groupby(lst) for x in islice(g, 2)]
print(output) # [1, 1, 2, 2, 4, 5, 6, 6, 7, 7]
You can do something like this:
from collections import Counter
max_accurance =2
list_A=[1,1,1,2,2,2,4,5,6,6,7,7,7]
d = dict(Counter(list_A))
new_list=[]
for k,v in d.items():
if v>=max_accurance:
new_list.extend([k]*max_accurance)
else:
new_list.append(k)
output
[1, 1, 2, 2, 4, 5, 6, 7, 7]
Most compressed way I could think of:
import operator as op
A=[1,1,1,2,2,2,4,5,6,6,7,7,7]
B = []
for elem in set(A):
B.extend([elem, elem]) if op.countOf(A, elem) > 2 else B.extend([elem])
Output:
[1, 1, 2, 2, 4, 5, 6, 7, 7]

Remove element if next element is the same from list in Python [duplicate]

I was curios about the question: Eliminate consecutive duplicates of list elements, and how it should be implemented in Python.
What I came up with is this:
list = [1,1,1,1,1,1,2,3,4,4,5,1,2]
i = 0
while i < len(list)-1:
if list[i] == list[i+1]:
del list[i]
else:
i = i+1
Output:
[1, 2, 3, 4, 5, 1, 2]
Which I guess is ok.
So I got curious, and wanted to see if I could delete the elements that had consecutive duplicates and get this output:
[2, 3, 5, 1, 2]
For that I did this:
list = [1,1,1,1,1,1,2,3,4,4,5,1,2]
i = 0
dupe = False
while i < len(list)-1:
if list[i] == list[i+1]:
del list[i]
dupe = True
elif dupe:
del list[i]
dupe = False
else:
i += 1
But it seems sort of clumsy and not pythonic, do you have any smarter / more elegant / more efficient way to implement this?
>>> L = [1,1,1,1,1,1,2,3,4,4,5,1,2]
>>> from itertools import groupby
>>> [key for key, _group in groupby(L)]
[1, 2, 3, 4, 5, 1, 2]
For the second part
>>> [k for k, g in groupby(L) if len(list(g)) < 2]
[2, 3, 5, 1, 2]
If you don't want to create the temporary list just to take the length, you can use sum over a generator expression
>>> [k for k, g in groupby(L) if sum(1 for i in g) < 2]
[2, 3, 5, 1, 2]
Oneliner in pure Python
[v for i, v in enumerate(your_list) if i == 0 or v != your_list[i-1]]
If you use Python 3.8+, you can use assignment expression :=:
list1 = [1, 2, 3, 3, 4, 3, 5, 5]
prev = object()
list1 = [prev:=v for v in list1 if prev!=v]
print(list1)
Prints:
[1, 2, 3, 4, 3, 5]
A "lazy" approach would be to use itertools.groupby.
import itertools
list1 = [1, 2, 3, 3, 4, 3, 5, 5]
list1 = [g for g, _ in itertools.groupby(list1)]
print(list1)
outputs
[1, 2, 3, 4, 3, 5]
You can do this by using zip_longest() + list comprehension.
from itertools import zip_longest
list1 = [1, 2, 3, 3, 4, 3, 5, 5].
# using zip_longest()+ list comprehension
res = [i for i, j in zip_longest(list1, list1[1:])
if i != j]
print ("List after removing consecutive duplicates : " + str(res))
Here is a solution without dependence on outside packages:
list = [1,1,1,1,1,1,2,3,4,4,5,1,2]
L = list + [999] # append a unique dummy element to properly handle -1 index
[l for i, l in enumerate(L) if l != L[i - 1]][:-1] # drop the dummy element
Then I noted that Ulf Aslak's similar solution is cleaner :)
To Eliminate consecutive duplicates of list elements; as an alternative, you may use itertools.zip_longest() with list comprehension as:
>>> from itertools import zip_longest
>>> my_list = [1,1,1,1,1,1,2,3,4,4,5,1,2]
>>> [i for i, j in zip_longest(my_list, my_list[1:]) if i!=j]
[1, 2, 3, 4, 5, 1, 2]
Plenty of better/more pythonic answers above, however one could also accomplish this task using list.pop():
my_list = [1, 2, 3, 3, 4, 3, 5, 5]
for x in my_list[:-1]:
next_index = my_list.index(x) + 1
if my_list[next_index] == x:
my_list.pop(next_index)
outputs
[1, 2, 3, 4, 3, 5]
Another possible one-liner, using functools.reduce (excluding the import) - with the downside that string and list require slightly different implementations:
>>> from functools import reduce
>>> reduce(lambda a, b: a if a[-1:] == [b] else a + [b], [1,1,2,3,4,4,5,1,2], [])
[1, 2, 3, 4, 5, 1, 2]
>>> reduce(lambda a, b: a if a[-1:] == b else a+b, 'aa bbb cc')
'a b c'

How can I find same values in a list and group together a new list?

From this list:
N = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
I'm trying to create:
L = [[1],[2,2],[3,3,3],[4,4,4,4],[5,5,5,5,5]]
Any value which is found to be the same is grouped into it's own sublist.
Here is my attempt so far, I'm thinking I should use a while loop?
global n
n = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5] #Sorted list
l = [] #Empty list to append values to
def compare(val):
""" This function receives index values
from the n list (n[0] etc) """
global valin
valin = val
global count
count = 0
for i in xrange(len(n)):
if valin == n[count]: # If the input value i.e. n[x] == n[iteration]
temp = valin, n[count]
l.append(temp) #append the values to a new list
count +=1
else:
count +=1
for x in xrange (len(n)):
compare(n[x]) #pass the n[x] to compare function
Use itertools.groupby:
from itertools import groupby
N = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
print([list(j) for i, j in groupby(N)])
Output:
[[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]
Side note: Prevent from using global variable when you don't need to.
Someone mentions for N=[1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 1] it will get [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5], [1]]
In other words, when numbers of the list isn't in order or it is a mess list, it's not available.
So I have better answer to solve this problem.
from collections import Counter
N = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
C = Counter(N)
print [ [k,]*v for k,v in C.items()]
You can use itertools.groupby along with a list comprehension
>>> l = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
>>> [list(v) for k,v in itertools.groupby(l)]
[[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]
This can be assigned to the variable L as in
L = [list(v) for k,v in itertools.groupby(l)]
You're overcomplicating this.
What you want to do is: for each value, if it's the same as the last value, just append it to the list of last values; otherwise, create a new list. You can translate that English directly to Python:
new_list = []
for value in old_list:
if new_list and new_list[-1][0] == value:
new_list[-1].append(value)
else:
new_list.append([value])
There are even simpler ways to do this if you're willing to get a bit more abstract, e.g., by using the grouping functions in itertools. But this should be easy to understand.
If you really need to do this with a while loop, you can translate any for loop into a while loop like this:
for value in iterable:
do_stuff(value)
iterator = iter(iterable)
while True:
try:
value = next(iterator)
except StopIteration:
break
do_stuff(value)
Or, if you know the iterable is a sequence, you can use a slightly simpler while loop:
index = 0
while index < len(sequence):
value = sequence[index]
do_stuff(value)
index += 1
But both of these make your code less readable, less Pythonic, more complicated, less efficient, easier to get wrong, etc.
You can do that using numpy too:
import numpy as np
N = np.array([1,2,2,3,3,3,4,4,4,4,5,5,5,5,5])
counter = np.arange(1, np.alen(N))
L = np.split(N, counter[N[1:]!=N[:-1]])
The advantage of this method is when you have another list which is related to N and you want to split it in the same way.
Another slightly different solution that doesn't rely on itertools:
#!/usr/bin/env python
def group(items):
"""
groups a sorted list of integers into sublists based on the integer key
"""
if len(items) == 0:
return []
grouped_items = []
prev_item, rest_items = items[0], items[1:]
subgroup = [prev_item]
for item in rest_items:
if item != prev_item:
grouped_items.append(subgroup)
subgroup = []
subgroup.append(item)
prev_item = item
grouped_items.append(subgroup)
return grouped_items
print group([1,2,2,3,3,3,4,4,4,4,5,5,5,5,5])
# [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]

Display random choice (Python)

I have a list[] of items from which I'd like to display one randomly, but the displayed item must not repeat more than once in last x requests.
list1 = item1, item2, item3, item4,
item5, item6, item7, item8, item9,
item 10
Display a random selection
from the list above
list2 = store the last displayed item in list2 which should only store 7
items, not more
Display a random
selection from the list but make
sure it doesn't exist in the
list2
Is that the right way to do it? Either way, I'd like to know how to limit a list to store only 7 items?
Thanks
collections.deque is the only sequence type in python that naturally supports being bounded (and only in Python 2.6 and up.) If using python 2.6 or newer:
# Setup
from collections import deque
from random import choice
used = deque(maxlen=7)
# Now your sampling bit
item = random.choice([x for x in list1 if x not in used])
used.append(item)
If using python 2.5 or less, you can't use the maxlen argument, and will need to do one more operation to chop off the front of the deque:
while len(used) > 7:
used.popleft()
This isn't exactly the most efficient method, but it works. If you need speed, and your objects are hashable (most immutable types), consider using a dictionary instead as your "used" list.
Also, if you only need to do this once, the random.shuffle method works too.
Is this what you want?
list1 = range(10)
import random
random.shuffle(list1)
list2 = list1[:7]
for item in list2:
print item
print list1[7]
In other words, look at random.shuffle(). If you want to keep the original list intact, you can copy it: list_copy = list1[:].
You could try using a generator function and call .next() whenever you need a new item.
import random
def randomizer(l, x):
penalty_box = []
random.shuffle(l)
while True:
element = l.pop(0)
# for show
print penalty_box, l
yield element
penalty_box.append(element)
if len(penalty_box) > x:
# penalty time over for the first element in the box
# reinsert randomly into the list
element = penalty_box.pop(0)
i = random.randint(0, len(l))
l.insert(i, element)
Usage example:
>>> r = randomizer([1,2, 3, 4, 5, 6, 7, 8], 3)
>>> r.next()
[] [1, 5, 2, 6, 4, 8, 7]
3
>>> r.next()
[3] [5, 2, 6, 4, 8, 7]
1
>>> r.next()
[3, 1] [2, 6, 4, 8, 7]
5
>>> r.next()
[3, 1, 5] [6, 4, 8, 7]
2
>>> r.next()
[1, 5, 2] [4, 3, 8, 7]
6
>>> r.next()
[5, 2, 6] [4, 3, 8, 7]
1
>>> r.next()
[2, 6, 1] [5, 3, 8, 7]
4
>>> r.next()
[6, 1, 4] [3, 8, 2, 7]
5
Something like:
# Setup
import random
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list2 = []
# Loop for as long as you want to display items
while loopCondition:
index = random.randint(0, len(list1)-1)
item = list1.pop(index)
print item
list2.append(item)
if(len(list2) > 7):
list1.append(list2.pop(0))
I'd use set objects to get a list of items in list1 but not in list2:
import random
list1 = set(["item1", "item2", "item3", "item4", "item5",
"item6", "item7", "item8", "item9", "item10"])
list2 = []
while True: # Or something
selection = random.choice(tuple(list1.difference(set(list2))))
print(selection)
list2.append(selection)
if len(list2) > 7:
list2 = list2[-7:]

Categories

Resources