Finding the first duplicate element in an ordered list - python

I'm new to coding and hit a wall as to what to do with my pseudo code.
I am defining a first duplicate function that for a = [1 2 2 3 4 4] it returns 2,
def firstDuplicate(a):
# put first element into new list (blist)
# check second element to blist
# if same, return element and end
# else, try next blist element
# if no next element, add to end of blist
# do the same with third element (counter) and so on until end of list
alist = list(a)
blist = list(a[1])
bleh = 1
comp = 2
if list(a[comp]) == blist[bleh]:
return list(a[comp]) # and end
if else bleh = bleh+1 # and repeat til last blist element
# to stop?
else blist = blist+list(a[2]) # append outside of blist?
This is what I've done so far. Any suggestions what I do next?

If I understand you correctly, you want to return the first number that appears a second time while you're iterating over the list. To achieve this I would use a set and check if the current item is already in the set, if yes return it, otherwise add the item to the set. (You could do that with a list, too, but less efficiently.)
def firstDuplicate(a):
set_ = set()
for item in a:
if item in set_:
return item
set_.add(item)
return None

In case if you would be interested in a single line code by list comprehension
a = [10,34,3,5,6,7,6,1,2]
print [n for i , n in enumerate(a) if n in a[i+1:] and n not in a[:i]][0]

a = [1, 2, 2, 3, 4, 4,]
def find_it(look_here):
have_seen = set()
for item in look_here:
if item in have_seen:
return item
have_seen.add(item)
find_it(a)
2

Related

Which item in list - Python

I am making a console game using python and I am checking if an item is in a list using:
if variable in list:
I want to check which variable in that list it was like list[0] for example. Any help would be appreciated :)
You can do it using the list class attribute index as following:
list.index(variable)
Index gives you an integer that matches the location of the first appearance of the value you are looking for, and it will throw an error if the value is not found.
If you are already checking if the value is in the list, then within the if statement you can get the index by:
if variable in list:
variable_at = list.index(variable)
Example:
foo = ['this','is','not','This','it','is','that','This']
if 'This' in foo:
print(foo.index('This'))
Outputs:
3
Take a look at the answer below, which has more complete information.
Finding the index of an item in a list
We may be inspired from other languages such as Javascript and create a function which returns index if item exists or -1 otherwise.
list_ = [5, 6, 7, 8]
def check_element(alist: list, item: any):
if item in alist:
return alist.index(item)
else:
return -1
and the usage is
check1 = check_element(list_, 5)
check2 = check_element(list_, 9)
and this one is for one line lovers
check_element_one_liner = lambda alist, item: alist.index(item) if item in alist else -1
alternative_check1 = check_element_one_liner(list_, 5)
alternative_check2 = check_element_one_liner(list_, 9)
and a bit shorter version :)
check_shorter = lambda a, i: a.index(i) if i in a else -1
Using a librairy you could use numpy's np.where(list == variable).
In vanilla Python, I can think of something like:
idx = [idx for idx, item in enumerate(list) if item == variable][0]
But this solution is not fool proof, for instance, if theres no matching results, it will crash. You could complete this using an if right before:
if variable in list:
idx = [idx for idx, item in enumerate(list) if item == variable][0]
else:
idx = None
I understand that you want to get a sublist containing only the elements of the original list that match a certain condition (in your example case, you want to extract all the elements that are equal to the first element of the list).
You can do that by using the built-in filter function which allows you to produce a new list containing only the elements that match a specific condition.
Here's an example:
a = [1,1,1,3,4]
variable = a[0]
b = list(filter(lambda x : x == variable, a)) # [1,1,1]
This answer assumes that you only search for one (the first) matching element in the list.
Using the index method of a list should be the way to go. You just have to wrap it in a try-except statement. Here is an alternative version using next.
def get_index(data, search):
return next((index for index, value in enumerate(data) if value == search), None)
my_list = list('ABCDEFGH')
print(get_index(my_list, 'C'))
print(get_index(my_list, 'X'))
The output is
2
None
assuming that you want to check that it exists and get its index, the most efficient way is to use list.index , it returns the first item index found, otherwise it raises an error so it can be used as follows:
items = [1,2,3,4,5]
item_index = None
try:
item_index = items.index(3) # look for 3 in the list
except ValueError:
# do item not found logic
print("item not found") # example
else:
# do item found logic knowing item_index
print(items[item_index]) # example, prints 3
also please avoid naming variables list as it overrides the built-in function list.
If you simply want to check if the number is in the list and print it or print it's index, you could simply try this:
ls = [1,2,3]
num = 2
if num in ls:
# to print the num
print(num)
# to print the index of num
print(ls.index(num))
else:
print('Number not in the list')
animals = ['cat', 'dog', 'rabbit', 'horse']
index = animals.index('dog')
print(index)

Python - Removing first two occurrences of element in list

The objective of this function is to remove the first two occurrences of n in a list.
Below is a code I had written but I still got it wrong after many hours. A friend advised me not to edit a list while iterating. However, I'm still stuck.
def remove_first_two(list,n):
if list == []:
return []
else:
count = 0
for ele in list:
if ele == n:
list.remove(ele)
count += 1
if count == 2:
break
return list
list = [1,2,2,3]
print(remove_first_two(list,2)) => [1,2,3] instead of [1,3]
Use list.remove twice with try-except. That will delete first two entries. Complexity O(n)
list_a = [1,2,3,4]
try:
list_a.remove(n)
list_a.remove(n)
# run a loop too, if it's more than 2
except:
pass
You can try find all indexes and del:
a = [1,2,3,2,3,2,4]
indices = [i for i, x in enumerate(a) if x == 2]
print(indices)
[1, 3, 5]
del a[indices[0]], a[indices[1]]
print(a)
[1, 3, 2, 2, 4]
First, don't use 'list' as its a key word in Python. Use something else, like 'alist'.
The code below does what you want and keeps the basic form of what you already have. You can of course also use the built-in .remove() method.
def remove_first_two(alist, n):
if alist == []:
return []
else:
count = 0
while count < 2:
for ele in alist:
if ele == n:
alist.remove(ele)
count += 1
return alist
alist = [1,2,2,3]
print(remove_first_two(alist,2)) # Output -> [1,3]
When your friend says "do not edit a list while iterating," he/she is right, and what he/she means is that you should create another list all together. What you are looking to do is the following:
def remove_first_two(list, n):
if list == []:
return []
else:
new_list = []
count = 0
for ele in list:
if ele == n:
if count >= 2:
new_list.append(ele)
count += 1
else:
new_list.append(ele)
return new_list
However, note that you can use use some built in functions to make your life much easier:
list.remove(x)
Remove the first item from the list whose value is equal to x. It raises a ValueError if there is no such item.
Therefore, you can more simply do:
def remove_first_two(list, n):
if list == []:
return []
for _ in range(2):
if n in list:
list.remove(n)
return list
Python updates the list if you change it while iterating.
In you test case with list = [1,2,2,3] when list[1] is deleted and Python updates list = [1,2,3]. Now Python understands you have iterated till index 1 and continues from index 2 which now contains 3. So Python encounters only one occurance of 2.
So heed your friends advice and do not edit list while iterating :)
Now you can use Python's in-built list.remove(element) to delete first ocuurence of a element. Repeat it 2 times for desired output.
Also O(n) with a single parse.
def remove_first_two(mylist,n):
counter = 0
def myfilter (i):
nonlocal counter,n
if counter > 2:
return True
else:
counter += 1
return (i != n)
return (list(filter(myfilter,mylist)))
This can also be done in python 3.8 using assignment expressions in a list comprehension:
data = [1,2,3,2,3,2,4]
count = 2
num = 2
[x for x in data if x != num or (count:=count-1) < 0]
Results:
[1, 3, 2, 2, 4]
Here is the reason why your program does not work:
When you remove an element, the for loop moves on to the next element, but by "moving on" it is actually skipping the element which now occupies the position of the deleted element. It skips the element right after the one you deleted.
The correct way to iterate over a list while you delete elements is making index progression explicit, by using a while loop instead of a for loop, and not increase the index when you delete an element:
i = 0
while i < len(my_list):
if condition:
my_list.pop(i)
else:
i += 1
However, none of this is necessary in your case! Notice that when you use my_list.remove(ele), you are not providing an index as you would with my_list.pop(i), so Python has to search for the first element that matches ele. Although remove will be slower than pop when used by themselves, here remove allows you not use any loops at all, simply do my_list.remove(n) twice!
Last touch: If your list has less than two elements matching n, one of the two my_list.remove(n) commands would return a ValueError. You can account for this exception, knowing that if it happens, your list is ready and requires no further action.
So the code you need is:
try:
my_list.remove(n)
my_list.remove(n)
except ValueError:
pass

Python Using Recursion to Traverse Through a Nested List With Conditions

Suppose I have the following:
def foo(lst):
current = 0
if(len(lst) == 0):
return current
first = bar(lst[0])
rest = foo(lst[1:])
if(first > current):
current = first
return current
if __name__ == "__main__":
lst1 = [2,4,6]
lst2 = [0,2,5,6,12]
lst3 = []
lst4 = [1]
lst5 = [2]
full_lst = [lst1, lst2, lst3, lst4, lst5]
print(foo(full_lst))
This function takes a nested list in the above structure as a parameter. The goal of the function is to traverse through this nested list structure recursively and apply a computation to each list. The function is also to keep track of each computation and eventually return the largest of these values obtained from the computations.
I believe I have some the basic structure complete, but I fail to see how I could use the function call on the smaller sub list and compare the value obtained from that with the one obtained from the previous function call.
Thanks.
How about something like this (if you don't want to pop your list):
def traverse_nested_list(my_nested_list):
results=[]
for my_item in my_nested_list:
if not isinstance(my_item, list):
# Insert condition
results.append(my_item)
if isinstance(my_item, list):
results.append(traverse_nested_list(my_item))
return results
# Nested list for testing
my_list = [1,2,3,4,5,[6,7,8,[9,1,2,3,4,5,6]]]
# Testing function
traverse_nested_list(my_list)
> [1,2,3,4,5,[6,7,8,[9,1,2,3,4,5,6]]]
Then you can just insert whatever condition you want at the value level. Here an example where we only keep values higher than five:
# Traverser with condition
def traverse_nested_list(my_nested_list):
results=[]
for my_item in my_nested_list:
if not isinstance(my_item, list):
if my_item > 5:
results.append(my_item)
if isinstance(my_item, list):
results.append(traverse_nested_list(my_item))
return results
# Nested list for testing
my_list = [1,2,3,4,5,[6,7,8,[9,1,2,3,4,5,6]]]
# Testing function
traverse_nested_list(my_list)
> [[6, 7, 8, [9, 6]]]
Recursion is fun. Focus on these two things:
If the answer is simple, return it!
Where does the recursion end?
Usually with some foundation like 'if this value in then that value out.'
If the answer is not simple:
break into parts
ask yourself the answer to the parts
recombine the parts into a result
So it's really just about working out where to end the loop, and how to divide/combine the parts.
In your sample you have the end point, but you don't use 'the rest'.
bar = len
def foo(lst):
if lst:
last = lst.pop()
return max(foo(lst), bar(last))
else:
return float('-inf')
if __name__ == "__main__":
lst1 = [2,4,6]
lst2 = [0,2,5,6,12]
lst3 = []
lst4 = [1]
lst5 = [2]
full_lst = [lst1, lst2, lst3, lst4, lst5]
print(foo([]), foo(full_lst))
# prints '-inf 5'

How To Tell if An Element In A List Is Itself A List? [Python]

As an exercise, I'm creating a code which recursively sums the elements of a list, including lists within lists.
Sample list: a = [1,2,[3,4],[5,6]]
Sample result: 21
My code is as follows:
a = [1,2,[3,4],[5,6]]
def sum(list):
if len(list[0]) == 1 and len(list) ==1: # case where list is [x]
return list[0]
elif len(list[0]) == 1 and len(list) > 1: # case where list is [x, etc]
return list[0] + sum(list[1:])
elif len(list[0]) > 1 and len(list == 1): # case where list is [[x,etc]]
return sum(list[0])
else: # case where list is [[x, etc], etc]
return sum(list[0]) + sum(list[1:])
print (sum(a))
However, when I try to run this I get the error "object of type 'int' has no length." I was under the impression that list[0] would just have a length of 1 if it's not a list in itself, but obviously, that doesn't work. What should I be doing instead to check whether an element in a list is itself a list?
What should I be doing instead to check whether an element in a list is itself a list?
if isinstance(x, list):
Common Gotchas You shouldn't name your own variables as list because you then overwrite the type list and function list()
Similarly for your function sum(). You wouldn't want to overwrite the sum() function that already handles a list of numbers.
Or another way would be hasattr(lst, "__len__")
from numbers import Number
def recur_sum(lst):
# Return single value immeadiately
if not lst or lst is None:
return 0
if isinstance(lst, Number):
return lst
head = None
tail = False
if hasattr(lst, "__len__"):
_size = len(lst)
if _size <= 0: # case where list is []
head = 0
elif _size >= 1:
if hasattr(lst[0], "__len__"): # case where list is [[x,etc]]
head = recur_sum(lst[0])
else: # case where list is [x]
head = lst[0]
tail = (_size > 1)
if not tail:
return head
else:
return head + recur_sum(lst[1:])
In short, you may use the isinstance function to check if an element is a list or not.
The follwoing code may serve as an example.
a = [1,2,[3,4],[5,6]]
a
Out[3]:
[1, 2, [3, 4], [5, 6]]
isinstance(a,list)
Out[4]:
True
isinstance(a[0],list)
Out[5]:
False
isinstance(a[2],list)
Out[6]:
True
For an item in the list you may change the if condition to if type(item) is list:
a = [1,2,[3,4],[5,6]]
for item in a:
if type(item) is list:
# do_something_with(item)
print(item)
and the output will look like this:
[3,4]
[5,6]
Make sure the reserved word list is not overwritten as a variable!

recursively remove adjacent duplicates in a list

I looked up and found a close example, but the answer found in this link: Remove adjacent duplicate elements from a list won't run the test cases for this problem. So this is all I have so far:
def remove_dups(thelist):
"""Returns: a COPY of thelist with adjacent duplicates removed.
Example: for thelist = [1,2,2,3,3,3,4,5,1,1,1],
the answer is [1,2,3,4,5,1]
Precondition: thelist is a list of ints"""
i = 1
if len(thelist) == 0:
return []
elif len(thelist) == 1:
return thelist
elif thelist[i] == thelist[i-1]:
del thelist[i]
return remove_dups(thelist[i:])
def test_remove_dups():
assert_equals([], remove_dups([]))
assert_equals([3], remove_dups([3,3]))
assert_equals([4], remove_dups([4]))
assert_equals([5], remove_dups([5, 5]))
assert_equals([1,2,3,4,5,1], remove_dups([1,2,2,3,3,3,4,5,1,1,1]))
# test for whether the code is really returning a copy of the original list
mylist = [3]
assert_equals(False, mylist is remove_dups(mylist))
EDIT while I do understand that the accepted answer linked above using itertools.groupby would work, I think it wouldn't teach me what's wrong with my code & and would defeat the purpose of the exercise if I imported grouby from itertools.
from itertools import groupby
def remove_dups(lst):
return [k for k,items in groupby(lst)]
If you really want a recursive solution, I would suggest something like
def remove_dups(lst):
if lst:
firstval = lst[0]
# find lowest index of val != firstval
for index, value in enumerate(lst):
if value != firstval:
return [firstval] + remove_dups(lst[index:])
# no such value found
return [firstval]
else:
# empty list
return []
Your assertion fails, because in
return thelist
you are returning the same list, and not a copy as specified in the comments.
Try:
return thelist[:]
When using recursion with list it is most of the time a problem of returning a sub-list or part of that list. Which makes the termination case testing for an empty list. And then you have the two cases:
The current value is different from the last one we saw so we want to keep it
The current value is the same as the last one we saw so we discard it and keep iterating on the "rest" of the values.
Which translate in this code:
l = [1,2,2,3,3,3,4,5,1,1,1]
def dedup(values, uniq):
# The list of values is empty our work here is done
if not values:
return uniq
# We add a value in 'uniq' for two reasons:
# 1/ it is empty and we need to start somewhere
# 2/ it is different from the last value that was added
if not uniq or values[0] != uniq[-1]:
uniq.append(values.pop(0))
return dedup(values, uniq)
# We just added the exact same value so we remove it from 'values' and
# move to the next iteration
return dedup(values[1:], uniq)
print dedup(l, []) # output: [1, 2, 3, 4, 5, 1]
problem is with your return statement,
you are returning
return remove_dups(thelist[i:])
output will be always last n single element of list
like for above soon,
print remove_dups([1,2,2,3,3,3,4,5,1,1,1])
>>> [1] #as your desired is [1,2,3,4,5,1]
which returns finally a list of single element as it don't consider Oth element.
here is recursive solution.
def remove_dups(lst):
if len(lst)>1:
if lst[0] != lst[1]:
return [lst[0]] + remove_dups(lst[1:])
del lst[1]
return remove_dups(lst)
else:
return lst

Categories

Resources