Duplicate integer detection - python

Update: Wow that was fast! Thank you all for your input, totally overlooked that I was comparing an indice to a value. I’m aware of the shorter methods, the course that I’m on hasn’t shown us the “set” method so I wanted to accomplish the assignment with what was taught. I would upvote all of your comments if I had enough reputation points, thank you all so much!!
First off im an uber-noob to python. I'm learning for the sake of improving my networking administrating skills. The purpose of my code is to remove integers that occur more than once, and to create a new array that doesn't have any duplicate integers. However my code adds in all duplicates, instead of skipping them.
Code:
import array
my_list = [1,1,1,1, 2, 3, 3, 4, 5, 6, 6, 3, 7]
unique_list = []
dupe_list = []
for i in range(len(my_list)):
if i not in unique_list:
unique_list.append(my_list[i])
print("unique array is ", unique_list, 'n', "dupe list: ", dupe_list)
Output:
unique array is [1, 1, 1, 2, 3, 3, 4, 5, 6, 6, 3, 7] n dupe list: []
So basically I have a for-loop that checks whether an integer that is in my_list is also in unique_list, if not then I want the code to add the integer in. However my code is adding every integer into the unique-list regardless of whether it is in there or not. Does the not in function not work the way I think it does?

you can remove integers that occur more then once using set
>>> my_list = [1,1,1,1, 2, 3, 3, 4, 5, 6, 6, 3, 7]
>>> list(set(my_list))
[1, 2, 3, 4, 5, 6, 7]
>>>

As others have pointed out, there are easier ways to accomplish what you're trying to do, but your bug is because you're confusing indices and values.
for i in range(len(my_list)):
if i not in unique_list:
unique_list.append(my_list[i])
In the above code, i is the index of each item in my_list, but you're comparing it against the values in unique_list. One of these things is not like the other!
If you wanted to iterate through by index, you need to use the subscript operator [] to get the value out of my_list:
for i in range(len(my_list)):
if my_list[i] not in unique_list:
unique_list.append(my_list[i])
It would however be simpler to just iterate through by value:
for v in my_list:
if v not in unique_list:
unique_list.append(v)
And of course it's simpler yet to just do:
unique_list = list(set(my_list))

You can use the function dict.fromkeys() to remove duplicates
>>> my_list = [1,1,1,1, 2, 3, 3, 4, 5, 6, 6, 3, 7]
>>> list(dict.fromkeys(my_list))
[1, 2, 3, 4, 5, 6, 7]

Related

inserted list changes even after being inserted

I wanted to create a list of lists
def func(m,n,l,t):
a=[i for i in range(m)]
b=[]
b.append(a)
a=swap(a)
b.append(a)
for i in b:
print(i)
def swap(l):
i,n=0,len(l)
while(i<n):
l[i],l[i+1]=l[i+1],l[i]
i+=2
return l
i created list a as my basis and append each modification i want to in the b list.
The problem is after i append the first list and modify it, the first one i inserted also changes the same as the second one i inserted.
the output of this code is this
[1, 0, 3, 2, 5, 4, 7, 6]
[1, 0, 3, 2, 5, 4, 7, 6]
what i want is when i performm the swap i dont want the first list to change
the output should look like this
[0, 1, 2, 3, 4, 5, 6, 7]
[1, 0, 3, 2, 5, 4, 7, 6]
if you could help, please thank you.
In place of append() method, you can try out extend() method which does the same as of append. but extend() method is mainly used for iterate items, as of in your case.
and also if you want to use only append, then take a copy of your variable first and append it, as you are changing in the first place, it is taking effect in the list too. So you can follow append into a list like, a.copy(). Hopes it helps
Please try out and share the feedback.
Thank you
Their are multiple code error you have done, for example:
you don't have to iterate over range object in order to get list, you could just...
a = list(range(m))
and also You don't have to run a while loop in order to iterate over two steps you could...
for i in range(0, len(l), 2):
see range for reference
also you didn't use any of n, l, t parameters of the func function.
THE ANSWER
when you pass the a variable to the swap function you are actually passing the class Object itself, so the swap function can change the value of the a variable (list class).
All you need is passing a copy of the a variable not the variable itself
a = swap(a.copy())
FINAL CODE
def swap(l):
for i in range(0, len(l), 2):
l[i],l[i+1]=l[i+1],l[i]
return l
def func(m):
a = list(range(m))
b = [a]
a = swap(a.copy())
b.append(a)
for i in b:
print(i)
func(8) # [0, 1, 2, 3, 4, 5, 6, 7], [1, 0, 3, 2, 5, 4, 7, 6]

How to append values to list?

I want to append my list with values for each loop iteration:
for i in range (4,10):
a_list = [1,2,3]
a_list = a_list.append(i)
The wanted output would be [1,2,3,4,5,6,7,8,9]. But I get None. Also printing type(a_list) after using .append() gives me <class'NoneType'>. What is the problem here ?
firstly, you have to mention a_list before for. instead, you will get [1, 2, 3, 9]. secondly, you give the a_list a value of a_list.append() function.
a_list = [1, 2, 3]
for i in range(4, 10):
a_list.append(i)
it is mainly because of the fact that list.append method does not return anything, it appends the given value to the list in-place.
we can confirm this by the simple example below
a = list()
b = a.append(5)
>> print(b)
None
>> print(a)
[5]
As matter of fact,there is a simpler and more performant way to achieve this
>> a_list = [1,2,3]
>> a_list += list(range(4, 10))
>> print(a_list)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Here, we first shape a new list from a iterator range(4, 10),
then we concate the two list together to get the list we want by adding the new list to the original list a_list.
by doing this, we can avoid the overhead caused by repeatedly call the list.append method in a for loop
a_list = []
for i in range (1,10):
a_list.append(i)
print(a_list)
Output
[1, 2, 3, 4, 5, 6, 7, 8, 9]
You have the wrong indentation on the loop.You need to add i at each iteration. Also, to get the list you want, you need to add 1, then 2, then 3, and so on. i this is what needs to be added. Put print(i) and print each iteration.
a_list = [1,2,3]
for i in range (4,10):
a_list.append(i)
print(a_list)
If you use your option, it will be correct to declare an array once. And then only add values. See below.
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Unique list of lists

I have a nested list as an example:
lst_a = [[1,2,3,5], [1,2,3,7], [1,2,3,9], [1,2,6,8]]
I'm trying to check if the first 3 indices of a nested list element are the same as other.
I.e.
if [1,2,3] exists in other lists, remove all the other nested list elements that contain that. So that the nested list is unique.
I'm not sure the most pythonic way of doing this would be.
for i in range(0, len(lst_a)):
if lst[i][:3] == lst[i-1][:3]:
lst[i].pop()
Desired output:
lst_a = [[1,2,3,9], [1,2,6,8]]
If, as you said in comments, sublists that have the same first three elements are always next to each other (but the list is not necessarily sorted) you can use itertools.groupby to group those elements and then get the next from each of the groups.
>>> from itertools import groupby
>>> lst_a = [[1,2,3,5], [1,2,3,7], [1,2,3,9], [1,2,6,8]]
>>> [next(g) for k, g in groupby(lst_a, key=lambda x: x[:3])]
[[1, 2, 3, 5], [1, 2, 6, 8]]
Or use a list comprehension with enumerate and compare the current element with the last one:
>>> [x for i, x in enumerate(lst_a) if i == 0 or lst_a[i-1][:3] != x[:3]]
[[1, 2, 3, 5], [1, 2, 6, 8]]
This does not require any imports, but IMHO when using groupby it is much clearer what the code is supposed to do. Note, however, that unlike your method, both of those will create a new filtered list, instead of updating/deleting from the original list.
I think you are missing a loop For if you want to check all possibilities. I guess it should like :
for i in range(0, len(lst_a)):
for j in range(i, len(lst_a)):
if lst[i][:3] == lst[j][:3]:
lst[i].pop()
Deleting while going throught the list is maybe not the best idea you should delete unwanted elements at the end
Going with your approach, Find the below code:
lst=[lst_a[0]]
for li in lst_a[1:]:
if li[:3]!=lst[0][:3]:
lst.append(li)
print(lst)
Hope this helps!
You can use a dictionary to filter a list:
dct = {tuple(i[:3]): i for i in lst}
# {(1, 2, 3): [1, 2, 3, 9], (1, 2, 6): [1, 2, 6, 8]}
list(dct.values())
# [[1, 2, 3, 9], [1, 2, 6, 8]]

Unable to create duplicate list from existing list using list comprehension with an if condition

I have a sorted list with duplicate elements like
>>> randList = [1, 2, 2, 3, 4, 4, 5]
>>> randList
[1, 2, 2, 3, 4, 4, 5]
I need to create a list that removes the adjacent duplicate elements. I can do it like:
>>>> dupList = []
for num in nums:
if num not in dupList:
dupList.append(num)
But I want to do it with list comprehension. I tried the following code:
>>> newList = []
>>> newList = [num for num in randList if num not in newList]
But I get the result like the if condition isn't working.
>>> newList
[1, 2, 2, 3, 4, 4, 5]
Any help would be appreciated.
Thanks!!
Edit 1: The wording of the question does seem to be confusing given the data I have provided. The for loop that I am using will remove all duplicates but since I am sorting the list beforehand, that shouldn't a problem when removing adjacent duplicates.
Using itertools.groupby is the simplest approach to remove adjacent (and only adjacent) duplicates, even for unsorted input:
>>> from itertools import groupby
>>> [k for k, _ in groupby(randList)]
[1, 2, 3, 4, 5]
Removing all duplicates while maintaining the order of occurence can be efficiently achieved with an OrderedDict. This, as well, works for ordered and unordered input:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(randList))
[1, 2, 3, 4, 5]
I need to create a list that removes the adjacent duplicate elements
Note that your for loop based solution will remove ALL duplicates, not only adjacent ones. Test it with this:
rand_list = [1, 2, 2, 3, 4, 4, 2, 5, 1]
according to your spec the result should be:
[1, 2, 3, 4, 2, 5, 1]
but you'll get
[1, 2, 3, 4, 5]
instead.
A working solution to only remove adjacent duplicates is to use a generator:
def dedup_adjacent(seq):
prev = seq[0]
yield prev
for current in seq[1:]:
if current == prev:
continue
yield current
prev = current
rand_list = [1, 2, 2, 3, 4, 4, 2, 5, 1]
list(dedup_adjacent(rand_list))
=> [1, 2, 3, 4, 2, 5, 1]
Python first evaluates the list comprehension and then assigns it to newList, so you cannot refer to it during execution of the list comprehension.
You can remove dublicates in two ways:-
1. Using for loop
rand_list = [1,2,2,3,3,4,5]
new_list=[]
for i in rand_list:
if i not in new_list:
new_list.append(i)
Convert list to set,then again convert set to list,and at last sort the new list.
Since set stores values in any order so when we convert set into list you need to sort the list so that you get the item in ascending order
rand_list = [1,2,2,3,3,4,5]
sets = set(rand_list)
new_list = list(sets)
new_list.sort()
Update: Comparison of different Approaches
There have been three ways of achieving the goal of removing adjacent duplicate elements in a sorted list, i.e. removing all duplicates:
using groupby (only adjacent elements, requires initial sorting)
using OrderedDict (all duplicates removed)
using sorted(list(set(_))) (all duplicaties removed, ordering restored by sorting).
I compared the running times of the different solutions using:
from timeit import timeit
print('groupby:', timeit('from itertools import groupby; l = [x // 5 for x in range(1000)]; [k for k, _ in groupby(l)]'))
print('OrderedDict:', timeit('from collections import OrderedDict; l = [x // 5 for x in range(1000)]; list(OrderedDict.fromkeys(l))'))
print('Set:', timeit('l = [x // 5 for x in range(1000)]; sorted(list(set(l)))'))
> groupby: 78.83623623599942
> OrderedDict: 94.54144410200024
> Set: 65.60372123999969
Note that the set approach is the fastest among all alternatives.
Old Answer
Python first evaluates the list comprehension and then assigns it to newList, so you cannot refer to it during execution of the list comprehension. To illustrate, consider the following code:
randList = [1, 2, 2, 3, 4, 4, 5]
newList = []
newList = [num for num in randList if print(newList)]
> []
> []
> []
> …
This becomes even more evident if you try:
# Do not initialize newList2
newList2 = [num for num in randList if print(newList2)]
> NameError: name 'newList2' is not defined
You can remove duplicates by turning randList into a set:
sorted(list(set(randlist)))
> [1, 2, 3, 4, 5]
Be aware that this does remove all duplicates (not just adjacent ones) and ordering is not preserved. The former also holds true for your proposed solution with the loop.
edit: added a sorted clause as to specification of required ordering.
In this line newList = [num for num in randList if num not in newList], at first the list will be created in right side then then it will be assigned to newList. That's why every time you check if num not in newList returns True. Becasue newList remains empty till the assignment.
You can try this:
randList = [1, 2, 2, 3, 4, 4, 5]
new_list=[]
for i in randList:
if i not in new_list:
new_list.append(i)
print(new_list)
You cannot access the items in a list comprehension as you go along. The items in a list comprehension are only accessible once the comprehension is completed.
For large lists, checking for membership in a list will be expensive, albeit with minimal memory requirements. Instead, you can append to a set:
randList = [1, 2, 2, 3, 4, 4, 5]
def gen_values(L):
seen = set()
for i in L:
if i not in seen:
seen.add(i)
yield i
print(list(gen_values(randList)))
[1, 2, 3, 4, 5]
This algorithm has been implemented in the 3rd party toolz library. It's also known as the unique_everseen recipe in the itertools docs:
from toolz import unique
res = list(unique(randList))
Since your list is sorted, using set will be the fasted way to achieve your goal, as follows:
>>> randList = [1, 2, 2, 3, 4, 4, 5]
>>> randList
[1, 2, 2, 3, 4, 4, 5]
>>> remove_dup_list = list(set(randList))
>>> remove_dup_list
[1, 2, 3, 4, 5]
>>>

insert top to bottom of list in python

I need to design a function that takes a list of int as a parameter and in that list we look at the last element it will have some value v, Then we take v cards from the top of the deck and put them above the bottom most card in the deck.
Here is an example:
>>> test_list = [1, 28, 3, 4, 27, 8, 7, 6, 5]
>>> insert_top_to_bottom(test_list)
>>> test_list = [8, 7, 6, 1, 28, 3, 4, 27, 5]
value = deck[-1] # value of the last element
I believe this will do
def insert_top_to_bottom(test_list, v):
return test_list[v : -1] + test_list[:v] + [test_list[-1]]
test_list = [1, 28, 3, 4, 27, 8, 7, 6, 5]
test_list = insert_top_to_bottom(test_list, 5)
print test_list
Here is my attempt, though you should next time show your own attempts.
Please note that I did not include any type of checking or avoiding errors. Just the basics.
def top_to_bottom(l):
last = l[len(l)-1]
move_these = l[:last]
move_these.append(l[len(l)-1])
del l[:last]
del l[len(l)-1]
l.extend(move_these)
I hope I could help.
EDIT
I didn't make it a one-line funtion so you can understand a bit better.
Since you asked, here is some more explanaition about slicing.
my_list[x:y] is a basic slice. This will output my_list from index x to (but excluding index y).
You can leave out either, which will just fill up that part as far as possible.
For example, using
my_list[:5]
will give you my_list from the beginning to (but excluding!) index 5.
If the list is [0, 1, 2, 3, 4, 5, 6], it will give [0, 1, 2, 3, 4]. If you want to get a list from a certain index until the end, you leave out the 'y' part. Like so:
my_list[3:]
Applying that on the list previously stated, you will get [3, 4, 5, 6].
I hope you understood! Comment if you have any more questions.

Categories

Resources