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
Related
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)
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
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'
i dont understand why my list in Nonetype. im trying to build a function that receives a list of int, which the first index is the pivot and then sorts the rest of the list so each int that is greater than the pivot will be on the right side and int that are smaller than the pivot will be on the left. the int's dont need to be sorted from smallest to biggest.
this is my code:
def divide_list(lst):
pivot = lst[0]
lst= lst.reverse()
for i in lst:
if i>pivot:
lst.append(i)
lst.remove(i)
return lst
thanks!
lst.reverse() reverses the list in place and returns None. Don't assign the return value back to lst:
def divide_list(lst):
pivot = lst[0]
lst.reverse()
for i in lst:
if i>pivot:
lst.append(i)
lst.remove(i)
return lst
If you don't want lst to be changed in-place, use a negative slice to get a new copy of the list in reverse order:
def divide_list(lst):
pivot = lst[0]
lst = lst[::-1]
for i in lst:
if i>pivot:
lst.append(i)
lst.remove(i)
return lst
This still will result in various problems; your approach won't work as you are altering the list in-place in the for loop. As you add and remove elements to the list, the iterator does not get updated and the list behaviour will not be what you expect.
Say you have a list [3, 4, 1, 2] after reversal, the pivot being 2. In the loop, the iterator used by the for loop looks at lst[0], and you'd move 3 to the end of the list by appending and removing. Now the list looks like [4, 1, 2, 3] and the loop advances to lst[1], so to the 1 value. 4 has been skipped altogether!
It's a bad idea to modify the list you're iterating over; it'll also get slow with larger input lists. Better to use a new list instead for building the result.
def divide_list(lst):
ret = [] # might replace with collections.deque
# for better performance with larger inputs
pivot = lst[0]
for i in reversed(lst):
if i > pivot:
ret.append(i)
else:
ret.insert(0, i)
return ret
Also, you can use 2 separate lists and then return them as a tuple, or concatenate them at the end:
def divide_list(lst):
left, right = [], []
pivot = lst[0]
for i in reversed(lst):
(right if i > pivot else left).append(i)
return left + right # or (left, right)
or you can even do 2 iterations over the list but avoid costly append or concatenation operations, by using a generator:
def divide_list(lst):
pivot = lst[0]
for i in reversed(lst):
if i < pivot: yield i
for i in reversed(lst):
if i >= pivot: yield i
new_list = list(divide_list(orig_list))
It looks like you're implementing a quicksort. If that's the case, I might do something like this:
def divide_list(lst):
pivot = lst[0]
left = []
right = []
for item in lst:
if item > pivot:
right.append(item)
else:
left.append(item)
return left, right
Of course, if you want a single list at the end, you could do something interesting like:
return left[::-1] + right
to reverse left and then concatenate that with right.
Others have provided you with an explanation for what is going wrong, but perhaps you'd consider a more straight-forward implementation?
def divide_list(lst):
pivot = lst[0]
return [i for i in lst if i <= pivot] + [i for i in lst if i > pivot]
Hi Im trying to create a search function in python, that goes through a list and searches for an element in it.
so far ive got
def search_func(list, x)
if list < 0:
return("failure")
else:
x = list[0]
while x > list:
x = list [0] + 1 <---- how would you tell python to go to the next element in the list ?
if (x = TargetValue):
return "success"
else
return "failure"
Well, you current code isn't very Pythonic. And there are several mistakes! you have to use indexes to acces an element in a list, correcting your code it looks like this:
def search_func(lst, x):
if len(lst) <= 0: # this is how you test if the list is empty
return "failure"
i = 0 # we'll use this as index to traverse the list
while i < len(lst): # this is how you test to see if the index is valid
if lst[i] == x: # this is how you check the current element
return "success"
i += 1 # this is how you advance to the next element
else: # this executes only if the loop didn't find the element
return "failure"
... But notice that in Python you rarely use while to traverse a list, a much more natural and simpler approach is to use for, which automatically binds a variable to each element, without having to use indexes:
def search_func(lst, x):
if not lst: # shorter way to test if the list is empty
return "failure"
for e in lst: # look how easy is to traverse the list!
if e == x: # we no longer care about indexes
return "success"
else:
return "failure"
But we can be even more Pythonic! the functionality you want to implement is so common that's already built into lists. Just use in to test if an element is inside a list:
def search_func(lst, x):
if lst and x in lst: # test for emptiness and for membership
return "success"
else:
return "failure"
Are you saying you want to see if an element is in a list? If so, there is no need for a function like that. Just use in:
>>> lst = [1, 2, 3]
>>> 1 in lst
True
>>> 4 in lst
False
>>>
This method is a lot more efficient.
If you have to do it without in, I suppose this will work:
def search_func(lst, x):
return "success" if lst.count(x) else "failure"
you dont need to write a function for searching, just use
x in llist
Update:
def search_func(llist,x):
for i in llist:
if i==x:
return True
return False
You are making your problem more complex, while solving any problem just think before starting to code. You are using while loops and so on which may sometimes becomes an infinite loop. You should use a for loop to solve it. This is better than while loop. So just check which condition helps you. That's it you are almost done.
def search_func(lst,x):
for e in lst: #here e defines elements in the given list
if e==x: #if condition checks whether element is equal to x
return True
else:
return False
def search(query, result_set):
if isinstance(query, str):
query = query.split()
assert isinstance(query, list)
results = []
for i in result_set:
if all(quer.casefold() in str(i).casefold() for quer in query):
results.append(i)
return results
Works best.