I have a list of numbers and I want to check if a definite sequence exists in that list. For example, for [1,1,2,2,3,3,3,4,5,5,6] how can I determine if the sequence 3-4-5 exists?
I tried using nested loops, but ran into a problem with break/continue. I am now reducing the list to its unique elements and seeing if my sequence exists:
ls = [1,1,2,2,3,3,3,4,5,5,6]
uniq_ls = []
for item in ls:
if item not in uniql:
uniq_ls.append(item)
for ii, item in enumerate(uniq_ls):
if item == 3:
if uniq_ls[ii+1] == 4:
if uniq_ls[ii+2] == 5:
print('yes, sequence exists')
Above method works, but I want to do this without reducing the original list to its unique elements.
How can I do this?
As pointed out by some folks, this method will work only if the original list is sorted.
It will not work for a list like [1,1,1,3,2,2,4,3,3,4,4,4,4,5,3,2,1]
I need it to work for a unsorted list like this one.
You can use this function:
def f(lst, seq):
for n in range(len(lst)-len(seq)+1):
if lst[n:n+len(seq)] == seq:
return True
return False
print(f([1,1,2,2,3,3,3,4,5,5,6], [3,4,5]))
Output:
True
You can also turn that into a one-liner:
def f(lst, seq):
return any(lst[n:n+len(seq)] == seq for n in range(len(lst)-len(seq)+1))
I worked out a solution to this when the list is unsorted. I am not sure if this is the most elegant, pythonic way -
List L1 is [1,1,1,3,2,2,4,3,3,4,4,4,4,5,3,2,1]
I will have an empty list L2 = [] and add first item of list to it.
Then I will append L2 with item from L1 if previous item is not the same as current item
So L2 eventually should look like [1,3,2,4,3,4,5,3,2,1]
From this list it will be easy to find a sequence 3-4-5.
New code:
l1 = [1,3,2,4,3,4,5,3,2,1]
l_uni = []
for ii, item in enumerate(l1):
if ii==0:
l_uni.append(item)
elif l1[ii] != l1[ii-1]:
l_uni.append(item)
for jj in range(0,len(l_uni)):
try:
if l_uni[jj] == 3:
if l_uni[jj+1] == 4:
if l_uni[jj+2] == 5:
print('found sequence')
break
except IndexError:
print('no sequence')
Related
def back_interleave(first, second):
if first == [] and second == []:
return []
elif first == []:
return second[::-1]
elif second == []:
return first[::-1]
else:
newlist = []
for i in range(len(first)-1, 0,-1):
newlist.append(first[i])
newlist.append(second[i])
for j in range(len(second)-len(first)-1,0,-1):
newlist.append(second[i])
return newlist
can anybody tells me what's wrong with my code towards this question.
I'm not exactly sure what's wrong with your code, but the second and third if-statements appear to use built-in list reversing functionality which the original problem forbids.
What I would do is determine the length of the longer list, then iterate through both lists backwards.
def back_interleave(first, second):
newlist = []
# You want to iterate through the length of the longer list
length = max(len(first), len(second))
for x in range(length):
# start appending elements from the back of the list
index = -1*(x+1)
if x < len(first):
newlist.append(first[index])
if x < len(second):
newlist.append(second[index])
return newlist
The problem in your code is when you use the range function, the stop value is exclusive i.e., the index 0 is becoming exclusive in your case. And also in the j loop the values at index i are being stored instead of the values at index j.
#CyanideTesla has given the code that works pretty well for your problem
Looking for advice on whether or not my code and idea are effective or I should be trying a different method. I'm not looking for full answers, rather hints. A simple "Keep going/trying" or "try something else" will suffice.
I have two parameters with the function, both are lists. They need to be of equal length to be compared, otherwise the program returns False.
An object in index i is moved to index (i+m)%k, where k is the length of the list, and m is how much the item in index i has moved.
My idea is this:
From the two lists of length k, I will check each index individually, and if it finds that the index has been moved (i+m)%k, it will add 1 to the counter.
There are 3 possibilities of cyclic permutations for a list of size 3, so if the counter hits 3, it will return a True.
def cyclic(lst1, lst2):
number_success = 0
if len(lst1) == len(lst2): # checks to see if lists are equal length
for i in range(len(lst1)): # starts with i index to check each spot
for j in range(len(lst1)): # starts with j index to test cycling
if lst1[i] == lst2[(i+j)%len(lst1)]:
number_success += 1
else:
continue
if number_success == len(lst1):
return(True)
else:
return(False)
else:
print("idiot")
How about concatenate lst1 with itself, then check if lst2 is found in lst1?
As an illustration using strings:
lst1="1234"
lst2="2341"
if lst2 in lst1+lst1:
print "yup"
else:
print "nope"
Corrected code in question:
def cyclic(lst1, lst2):
number_success = 0
if len(lst1) == len(lst2): # checks to see if lists are equal length
for j in range(len(lst1)): # starts with j index to test cycling
for i in range(len(lst1)): # starts with i index to check each spot
if lst1[i] == lst2[(i+j)%len(lst1)]:
number_success += 1
if number_success == len(lst1):
return True
return False
else:
print("idiot")
Your algorithm will not work. You are comparing every item in lst1 with every item in lst2 and accumulating the matches. Your approach doesn't account for the order of the items. You are essentially doing
set(lst1) == set(lst2)
I added a print statement in the inner loop to watch what was happening. I have found printing variables, calculation and comparison results effective when trying to figure out what I am doing.
print(lst1[i], lst2[(i+j)%len(lst1)], lst1[i] == lst2[(i+j)%len(lst1)])
You can check by comparing the two lists, if they are equal then there is a cycle, if they are not equal, rotate one list and repeat, if after len(list) rotations there isn't a match then there isn't a cycle. Something like this
... code deleted ...
How about recycling the list2 to list1 and check
def cyclic(list1, list2):
if set(list1) != set(list2):
return False
elem01_idx = list2.index(list1[0])
recycled_list2 = list2[elem01_idx:] + list2[:elem01_idx]
return list1 == recycled_list2
list1 = [1,2,3,4]
list2 = [2,3,4,1]
print(cyclic(list1, list2))
# True
I'm trying to print all elements in a sorted list that only occur once.
My code below works but I'm sure there is a better way:
def print_unique(alist):
i = 0
for i in range(len(alist)):
if i < (len(alist)-1):
if alist[i] == alist[i+1]:
i+=1
if alist[i] == alist[i-1]:
i+=1
elif alist[i] == alist[i-1]:
i+=1
else:
print alist[i]
else:
if alist[-1]!= alist[-2]:
print alist[-1]
randomlist= [1,2,3,3,3,4,4,5,6,7,7,7,7,8,8,8,9,11,12,14,42]
print_unique(randomlist)
This produces
1
2
5
6
9
11
12
14
42
e.g. all values that only appear once in a row.
You could use the itertools.groupby() function to group your inputs and filter on groups that are one element long:
from itertools import groupby
def print_unique(alist):
for elem, group in groupby(alist):
if sum(1 for _ in group) == 1: # count without building a new list
print elem
or if you want to do it 'manually', track the last item seen and if you have seen it more than once:
def print_unique(alist, _sentinel=object()):
last, once = _sentinel, False
for elem in alist:
if elem == last:
once = False
else:
if once:
print last
last, once = elem, True
if last is not _sentinel and once:
print last
You may want to replace the print statements with yield and leave printing to the caller:
def filter_unique(alist):
for elem, group in groupby(alist):
if sum(1 for _ in group) == 1: # count without building a new list
yield elem
for unique in filter_unique(randomlist):
print unique
This question seems to have duplicates.
If you do not wish to preserve the order of your list, you can do
print list(set(sample_list))
You can also try,
unique_list = []
for i in sample_list:
if i not in unique_list:
unique_list.append(i)
EDIT:
In order to print all the elements in the list so that they appear once in a row, you can try this
print '\n'.join([str(i) for i in unique_list])
And, as #martijn-pieters mentioned it in the comments, the first code was found to be very fast compared to the second one, when I did a small benchmark. On a list of 10^5 elements, the second code took 63.66 seconds to complete whereas the first one took a mere 0.2200 seconds. (on a list generated using random.random())
you can do by this:
print (set(YOUR_LIST))
or if you need a list use this:
print (list(set(YOUR_LIST)))
Sets are lists containing unique items. If you construct a set from the array, it will contain only the unique items:
def print_unique(alist):
print set( alist )
The input list does not need to be sorted.
I apologize for the poor title. Wasn't sure exactly how to word my question.
I have code below which uses a list of tuples called propadd. The if statement tests the tuples for matching conditions. If the match matches to only 1 tuple from the list of tuples, it executes the exact same code as that in the if statement so as to assign this matching tuple to variable v in order to update the cursor rows with values from this matching tuple. I would like to know if there's a way to get rid of the assignment of the exact same code to v after the if statement. Is it possible to assign the list to v in the if statement while checking for the length of the matches? This is part of a larger amount of code that follows this methodology. I believe that doing this will make my code faster.
if len([item for item in propadd if item[0]==row1[8] and harversine(custx,custy,item[2],item[3])<1500]) == 1:
v=[item for item in propadd if item[0]==row1[8] and harversine(custx,custy,item[2],item[3])<1500]
row1[1]=v[0][1]
row1[2]=v[0][2]
elif len([item for item in custadd if item[0]==row1[4]]) == 1:
k=[item for item in custadd if item[0]==row1[4]]
row1[1]=k[0][1]
row1[2]=k[0][2]
elif len([item for item in numlist if re.search(r"^[0-9]+(?=\s)",row1[0]) is not None and item[0]==re.search(r"^[0-9]+(?=\s)",row1[0]).group()]) == 1
m=[item for item in numlist if re.search(r"^[0-9]+(?=\s)",row1[0]) is not None and item[0]==re.search(r"^[0-9]+(?=\s)",row1[0]).group()]
row1[1]=m[0][1]
row1[2]=m[0][2]
It will make your code slightly faster, and what is much more important, more readable and less error prone. Whether the list you create passes the test len(...) == 1 or not, it is computed. So why not just compute it once? Of course you will have to replace elif with else-if:
# Compute v
v = [item for item in propadd if item[0]==row1[8] and harversine(custx,custy,item[2],item[3])<1500]
if len(v) == 1:
row1[1]=v[0][1]
row1[2]=v[0][2]
else:
# If v fails, compute k
k = [item for item in custadd if item[0]==row1[4]]
if len(k) == 1:
row1[1]=k[0][1]
row1[2]=k[0][2]
else:
# If k fails, compute m
m = [item for item in numlist if re.search(r"^[0-9]+(?=\s)",row1[0]) is not None and item[0]==re.search(r"^[0-9]+(?=\s)",row1[0]).group()]
if len(m) == 1:
row1[1]=m[0][1]
row1[2]=m[0][2]
Coming from C, this is much more cumbersome than if(v = (....)) { } else .... However, there is another way to do this. You can use the fact that each expression in the list comprehensions is a generator:
v = (item for item in propadd if item[0]==row1[8] and harversine(custx,custy,item[2],item[3])<1500)
k = (item for item in custadd if item[0]==row1[4])
m = (item for item in numlist if re.search(r"^[0-9]+(?=\s)",row1[0]) is not None and item[0]==re.search(r"^[0-9]+(?=\s)",row1[0]).group())
for gen in (v, k, m):
l = list(gen)
if len(l) == 1:
row1[1] = l[0][1]
row1[2] = l[0][2]
break
In this case, the expressions v, k, m are generators, which are objects that are lazily evalutated iterables. They are not actually computing the list. You can go through each one and assign the one that matches when it is found, ignoring the others. The list is not computed until the statement l = list(gen). I think the second approach is much more Pythonic because it uses a single for loop no matter how many conditions you have, instead of a sequence of else statements marching off the page.
Working in Python, how would I write code to remove negatives from an unknown list of integers using for loops and if statements?
def mod_lis (list):
for i in range(len(list)):
if list[i] < 0:
del list[i]
return list
The problem with your code is that you modify your list during your for loop. The result is that you jump over elements this way and get an IndexError soon since your list has been shortened.
You can do this with this list comprehension:
mylist = [val for val in mylist if val>=0]
You can use filter() and a lambda function:
my_list = filter(lambda x : x >= 0, mylist)
It's better to make a copy of the list without selected items, but if you have to modify in place, try this:
def remove_negatives(list):
pos = 0
for item in list:
if item >= 0:
list[pos] = item
pos += 1
del list[pos:]