Related
Want to remove duplicate in the python list, just want to keep unique values
l=[3,2,3,4,5,6,1,2]
for i in range(len(l)):
if i in l[:i+1]:
l.pop(i-2)
If am puting pop(i).... it is giving pop out of range
while moving forward in through loop in list, am trying to check if they are present in previous part l[0:i+1], if it's present pop the current item.
Don't wan't to use set!!!
You can use this method by converting the list into the set and then converting it into the list again.
The set data structure contains only unique elements so by converting the into the set we are eliminating all the duplicate elements but the data type will be set.
So to get the original data type we need to convert the set to a list again. Now we have a list without any duplicate elements.
l=[3,2,3,4,5,6,1,2]
list(set(l))
Output
[1, 2, 3, 4, 5, 6]
Since you've mentioned not to use any other data structure, I am providing a solution that runs in quadratic time with respect to the length of the list.
l = [3, 2, 3, 4, 5, 6, 1, 2]
for i in range(len(l)):
for j in range(len(l) - 1, i, -1):
if l[i] == l[j]:
l.pop(j)
print(l)
How it works:
The outer loop with variable i is used to iterate over the list. The nested loop with variable j is used to check if the item is present in the slice after the index i. Every such index is discarded.
Note that we are iterating backwards in the nested loop to avoid index out-of-range situations.
This implementation will not alter the order of the elements and doesn't use any extra space.
l=[3,2,3,4,5,6,1,2]
loc = 0
itr = 0
while loc < len(l):
# test if the item in the current position already exists in l[:loc]
if l[loc] in l[:loc]:
# remove the current item
l.pop(loc)
else:
# move the loc variable to test the next item
loc += 1
# if we removed an item we test the new item that gets pushed into this position
itr+=1
print('itr:{}, loc:{}, l:{}'.format(itr, loc, l))
print('Result:{}'.format(l))
itr:1, loc:1, l:[3, 2, 3, 4, 5, 6, 1, 2]
itr:2, loc:2, l:[3, 2, 3, 4, 5, 6, 1, 2]
itr:3, loc:2, l:[3, 2, 4, 5, 6, 1, 2]
itr:4, loc:3, l:[3, 2, 4, 5, 6, 1, 2]
itr:5, loc:4, l:[3, 2, 4, 5, 6, 1, 2]
itr:6, loc:5, l:[3, 2, 4, 5, 6, 1, 2]
itr:7, loc:6, l:[3, 2, 4, 5, 6, 1, 2]
itr:8, loc:6, l:[3, 2, 4, 5, 6, 1]
Result:[3, 2, 4, 5, 6, 1]
If we typecast a list into set then also we can remove duplicates
example:
x= [1,1,2,1,2,1,3,4]
here x is a list which contains duplicates
y = set(x)
print(y)
output - {1,2,3,4}
So, in this example when I type casted x to set and stored output in y , then y as a set contains only unique elements
Also if we want to convert this set back to list then we can do this:
z= list(y)
I have a list
x=[0,1,1,2,3,5,8,3,1]
I want to remove list items at odd index only
i.e. x[1],x[3],x[5],... etc
should be removed.
My resulting list should be
x=[0,1,3,8,1]
def odd_indexed_list(x):
...
x = [0, 1, 1, 2, 3, 5, 8, 3, 1]
# ^ ^ ^ ^ ^
odd_indexed_list(x)
print(x)
# >> [0, 1, 3, 8, 1]
I want to loop till only one item in the list is remaining.
Here's my version of odd_indexed_list()
def odd_indexed_list(x):
n=len(x)
while(n>1):
for j in range(1,n+1,2):
del x[i]
The error is - IndexError: list assignment index out of range
You are trying to access an index that might not exist anymore. i.e.: do not modify a list while iterating over it. Examining your initial control flow, let's look at a simple example:
x = [1, 2, 3]
This has len of 3. However, when you do the following:
del x[1]
x now has the value [1, 3]. The len has changed, and so your final index 2, which was valid at the start of your loop is now invalid. The index is not tied to the state of your list.
With a quick refactor, this can easily be accomplished with a list comprehension:
x = list(range(20))
x = [a for i, a in enumerate(x) if not i%2]
x
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Where enumerate will produce pairs (index, element) of an iterable, and the not i % 2 will ensure that the index is divisible by 2 (not odd). enumerate produces a generator that you can iterate over, and the index in the index, element pairs is directly tied to the original state, allowing you to accurately skip over elements you do not want
Assuming that you made a mistake by including index 0, this should do it:
x = [0, 1, 1, 2, 3, 5, 8, 3, 1]
while len(x) != 1:
x = x[::2][1:]
Printing x yields the output:
[8]
The process you've described, "remove odd elements from the list and continue until there is only one element remaining", will always give you a list containing one element. So the most efficient way to do it is just to figure out which element that will be, and just take that element from the list. It'll always be the first element. (Because each pass removes x[1] and possibly some other elements x[i] with i > 1, it never removes x[0], so repeating enough times will eventually remove all the elements after x[0] leaving you just x[0] as your only remaining entry). So:
> x = [0, 1, 2, 3, 4]
> print(x[:1])
[0]
However, perhaps you don't need to keep going, you just want the result after one step? In that case:
Python has a way to get every Nth element in a list:
> x = [0, 1, 2, 3, 4]
> print(x[::2])
[0, 2, 4]
Or to get the other half of the list:
> x = [0, 1, 2, 3, 4]
> print(x[1::2])
[1, 3]
You can replace the contents of a list like this:
> x = [0, 1, 2, 3, 4]
> x[:] = [9, 8, 7]
> print(x)
[9, 8, 7]
Putting those together:
> x = [0, 1, 2, 3, 4]
> x[:] = x[::2]
> print(x)
[0, 2, 4]
I faced some problem with solving the next problem:
We have a list of elements (integers), and we should return a list consisting of only the non-unique elements in this list. Without changing order of the list
I think the best way is to delete or remove all unique element.
Take note that I just start to learn python and would like only the simplest solutions.
Here is my code:
def checkio(data):
for i in data:
if data.count(i) == 1: #if element seen in the list just ones, we delet this el
ind = data.index(i)
del data[ind]
return data
Your function can be made to work by iterating over the list in reverse:
def checkio(data):
for index in range(len(data) - 1, -1, -1):
if data.count(data[index]) == 1:
del data[index]
return data
print(checkio([3, 3, 5, 8, 1, 4, 5, 2, 4, 4, 3, 0]))
[3, 3, 5, 4, 5, 4, 4, 3]
print(checkio([1, 2, 3, 4]))
[]
This works, because it only deletes numbers in the section of the list that has already been iterated over.
Just I used list Comprehensions.
def checkio(data):
a=[i for i in data if data.count(i)>1]
return a
print checkio([1,1,2,2,1,1,1,3,4,5,6,7,8])
You can implement a OrderedCounter, eg:
from collections import OrderedDict, Counter
class OrderedCounter(Counter, OrderedDict):
pass
data = [1, 3, 1, 2, 3, 5, 8, 1, 5, 2]
duplicates = [k for k, v in OrderedCounter(data).items() if v > 1]
# [1, 3, 2, 5]
So you count the occurrence of each value, then filter on if it has a frequency of more than one. Inheriting from OrderedDict means the order of the original elements is preserved.
Going by comments, you want all duplicated elements reserved, so you can pre-build a set of the duplicate entries, then re-iterate your original list, eg:
from collections import Counter
data = [1, 3, 1, 2, 3, 5, 8, 1, 5, 2]
duplicates = {k for k, v in Counter(data).items() if v > 1}
result = [el for el in data if el in duplicates]
# [1, 3, 1, 2, 3, 5, 1, 5, 2]
Try this:
>>> a=[1,2,3,3,4,5,6,6,7,8,9,2,0,0]
>>> a=[i for i in a if a.count(i)>1]
>>> a
[2, 3, 3, 6, 6, 2, 0, 0]
>>> a=[1, 2, 3, 1, 3]
>>> a=[i for i in a if a.count(i)>1]
>>> a
[1, 3, 1, 3]
>>> a=[1, 2, 3, 4, 5]
>>> a=[i for i in a if a.count(i)>1]
a
[]
def checkio(data):
lis = []
for i in data:
if data.count(i)>1:
lis.append(i)
print(lis)
checkio([1,2,3,3,2,1])
Yeah it's a bit late to contribute to this thread but just wanted to put it there on the net for anyone else use.
Following what you have started, iterating on the list of integers, but not counting or deleting elements, try just testing if the element has already been seen, append it to a list of duplicated elements:
def checkio(data):
elements = []
duplicates = []
for i in data:
if i not in elements:
elements.append(i)
else:
if i not in duplicates:
duplicates.append(i)
return duplicates
d = [1, 3, 1, 2, 3, 5, 8, 1, 5, 2]
print (checkio(d))
#[1, 3, 5, 2]
numbers = [1, 1, 1, 1, 3, 4, 9, 0, 1, 1, 1]
x=set(numbers)
print(x)
You can use the set key word too to get the desired solution.
I used an integer and bool to check every time the list was modified within a while loop.
rechecks = 1
runscan = True
while runscan == True:
for i in data:
if data.count(i) <2:
data.remove(i)
rechecks+=1
#need to double check now
if rechecks >0:
runscan = True
rechecks-=1
else:
runscan = False
return data
Would it not be easier to generate a new list?
def unique_list(lst):
new_list = []
for value in lst:
if value not in new_list:
new_list.append(value)
return new_list
lst = [1,2,3,1,4,5,1,6,2,3,7,8,9]
print(unique_list(lst))
Prints [1,2,3,4,5,6,7,8,9]
i am confuse at some point in my python code, i am trying to build a program which return the cumulative sum, that is where is the ith element is the sun of first i+1 elements from the origional list. So cunmulative sum of [1,2,3] is [1,3,6], i tried to build program and its working but for first element its adding last element as previous element, that made me think that is structure of python list something circle??
h=[]
a=[1,2,3,4,5,6]
for i in range(len(a)):
d=a[i]+(a[i-1]+1)
h.append(d)
print(h)
Result
[8, 4, 6, 8, 10, 12]
The culprit is with a[i - 1] in the 0th iteration:
d = a[i] + (a[i - 1] + 1)
What actually happens is that i - 1 is reduced to -1, and in python, a[-1] refers to the last element in the list:
In [568]: l = [1, 2, 3, 4]
In [569]: l[-1]
Out[569]: 4
The solution here would be to start your loop from 1. Alternatively, you would consider the use of a temp variable, as mentioned here:
a = [1, 2, 3, 4, 5, 6]
h = []
cumsum = 0
for i in a:
cumsum += i
h.append(cumsum)
print(h)
[1, 3, 6, 10, 15, 21]
As a side, if you're using numpy, this is as simple as a single function call with np.cumsum:
h = np.cumsum([1, 2, 3, 4, 5, 6])
print(h)
array([ 1, 3, 6, 10, 15, 21])
Just wanted to add that you could use itertools.accumulate to accumulate the results of a binary operation, in this case, addition. Note, itertools.accumulate actually defaults to addition:
>>> a = [1, 2, 3, 4, 5, 6]
>>> a = [1, 2, 3, 4, 5, 6]
>>> import itertools
>>> list(itertools.accumulate(a))
[1, 3, 6, 10, 15, 21]
But you could pass it a binary operation and do a cumulative product, for example:
>>> list(itertools.accumulate(a ,lambda x, y: x*y))
Better yet, harness the power of the operator module:
>>> list(itertools.accumulate(a, operator.add)) #cumulative sum
[1, 3, 6, 10, 15, 21]
>>> list(itertools.accumulate(a, operator.mul)) #cumulative product
[1, 2, 6, 24, 120, 720]
>>> list(itertools.accumulate(a, operator.truediv)) #cumulative quotient
[1, 0.5, 0.16666666666666666, 0.041666666666666664, 0.008333333333333333, 0.001388888888888889]
>>> list(itertools.accumulate(a, operator.floordiv)) #cumulative floor div
[1, 0, 0, 0, 0, 0]
Yes - it is a little like that. In python a[-1] gives you the last element of the list.
If you seed the result with the first item your code and start from 1 rather than 0 can be made to work:
a=[1,2,3,4,5,6]
h=[a[0]]
for i in range(1,len(a)):
d=a[i]+(h[i-1])
h.append(d)
print(h)
Lists are not circular, but the can be referenced from either the beginning or the end. You can use [-1] to reference from the end of the list.
But, if you try to reference the 20th element of a list that only has 10 elements, you will receive an error. If lists were circular, it would refer to the 10th element, but it does not.
What you want is this, I believe:
a = [1,2,3,4,5,6]
h = []
index = 0
for i in range(len(a) - 1):
first = a[index]
second = a[index + 1]
summation = first + second
h.append(summation)
index += 1
print(h)
I am trying remove duplicate elements from the list, whose number of duplicates is odd.
For example for the following list: [1, 2, 3, 3, 3, 5, 8, 1, 8] I have 1 duplicated 2 times, 3 duplicated 3 times, and 8 duplicated 2 times. So 1 and 8 should be out and instead of 3 elements of 3 I need to leave only 1.
This is what I came up with:
def remove_odd_duplicates(arr):
h = {}
for i in arr:
if i in h:
h[i] += 1
else:
h[i] = 1
arr = []
for i in h:
if h[i] % 2:
arr.append(i)
return arr
It returns everything correctly: [2, 3, 5], but I do believe that this can be written in a nicer way. Any ideas?
You can use collections.Counter and list comprehension, like this
data = [1, 2, 3, 3, 3, 5, 8, 1, 8]
from collections import Counter
print [item for item, count in Counter(data).items() if count % 2]
# [2, 3, 5]
The Counter gives a dictionary, with every element in the input iterable as the keys and their corresponding counts as the values. So, we iterate over that dict and check if the count is odd and filter only those items out.
Note: The complexity of this solution is still O(N), just like your original program.
If order doesn't matter:
>>> a = [1, 2, 3, 3, 3, 5, 8, 1, 8]
>>> list(set([x for x in a if a.count(x)%2 == 1]))
[2, 3, 5]
The list comprehension [x for x in a if a.count(x)%2 == 1] returns only the elements which appear an odd number of times in the list. list(set(...)) is a common way of removing duplicate entries from a list.
you can possibly use scipy.stats.itemfreq:
>>> from scipy.stats import itemfreq
>>> xs = [1, 2, 3, 3, 3, 5, 8, 1, 8]
>>> ifreq = itemfreq(xs)
>>> ifreq
array([[1, 2],
[2, 1],
[3, 3],
[5, 1],
[8, 2]])
>>> i = ifreq[:, 1] % 2 != 0
>>> ifreq[i, 0]
array([2, 3, 5])