Test for consecutive numbers in list - python

I have a list that contains only integers, and I want to check if all the numbers in the list are consecutive (the order of the numbers does not matter).
If there are repeated elements, the function should return False.
Here is my attempt to solve this:
def isconsecutive(lst):
"""
Returns True if all numbers in lst can be ordered consecutively, and False otherwise
"""
if len(set(lst)) == len(lst) and max(lst) - min(lst) == len(lst) - 1:
return True
else:
return False
For example:
l = [-2,-3,-1,0,1,3,2,5,4]
print(isconsecutive(l))
True
Is this the best way to do this?

Here is another solution:
def is_consecutive(l):
setl = set(l)
return len(l) == len(setl) and setl == set(range(min(l), max(l)+1))
However, your solution is probably better as you don't store the whole range in memory.
Note that you can always simplify
if boolean_expression:
return True
else:
return False
by
return boolean_expression

A better approach in terms of how many times you look at the elements would be to incorporate finding the min, max and short circuiting on any dupe all in one pass, although would probably be beaten by the speed of the builtin functions depending on the inputs:
def mn_mx(l):
mn, mx = float("inf"), float("-inf")
seen = set()
for ele in l:
# if we already saw the ele, end the function
if ele in seen:
return False, False
if ele < mn:
mn = ele
if ele > mx:
mx = ele
seen.add(ele)
return mn, mx
def isconsecutive(lst):
"""
Returns True if all numbers in lst can be ordered consecutively, and False otherwise
"""
mn, mx = mn_mx(lst)
# could check either, if mn is False we found a dupe
if mn is False:
return False
# if we get here there are no dupes
return mx - mn == len(lst) - 1

Related

Find the max number in a list

I wrote some functions to find the maximum number of a list. If my list contains numbers and other types it gets only the numbers and finds the maximum, if my list is empty then it returns None. My only problem is that it always returns the number 7 instead of the 32 which is bigger than 7
#gets the numbers
def getint( l ):
result=[]
x=0
if not l:
print('The list is empty')
else:
while x!=len(l):
if l[x].isdigit() == True:
result.append(l[x])
x += 1
return result
#returns true or false
def all_ints( l ):
result=[]
x=0
y=0
for i in range(len(l)):
if l[i].isdigit() == True:
continue
else:
y=1
if(y==1):
result.append(False)
else:
result.append(True)
return result
#get the maximum
def max_int( l ):
x=0
if not l:
max='none'
else:
max = l[0]
while x!=len(l):
if l[x] > max:
max = l[x]
x+=1
return max
#return true or false if its empty
def isEmpty( l ):
if not l:
return True
else:
return False
def check( l ):
max=0
val=isEmpty(l)
if(val==True):
max='None'
elif(all_ints(l)==True):
max=max_int(l)
else:
new_l=getint(l)
max=max_int(new_l)
return max
print(check(['4','5','6','7', '32']))
In your max_int function, you compare two strings instead of numbers. The problem is, that 32 > 7 == True, but '32' > '7' == False. More on comparing strings.
Also, I would suggest that you just convert to integer and check for errors and then look for maximal number.
def max_num(l):
int_arr = []
for i in l:
try:
int_arr.append(int(i))
except:
pass
return max(int_arr)
print(max_num(['4','5','6','7', '32']))
The error is that you are defining the numbers as characters, and in reality the first character is compared, if you put them as numbers really, your code will result in 32
Fix this
print(check(['4','5','6','7', '32']))
for
print(check([4,5,6,7,32]))

Python check if indefinite number of consecutive elements in a list satisfy a condition

Basically I am playing around with nested lists, and would like for a given input n, to find if n consecutive elements in the list satisfy a predetermined condition.
For example:
n = 3
lst = [[1,2,3],[6,7,8],[4,5,6],[1,3,4,5]]
And I would like to know if there are n consecutive sublists within lst that have length greater than or equal to 3 (Or some other condition). What is the most efficient way to find firstly:
Is the condition satisfied
The range of indices for when condition is satisfied n times
An example output for my illustrative example would be:
True
index_range = (0,2) #Only need the first instance when n consec achieved
Any help would be greatly appreciated, preferably code which doesn't rely too heavily on inbuilt Python libraries such as itertools or numpy as I am new to Python and would like to better understand how such a process works. Thanks in advance!
different conditionals, one loop, constant memory usage, early exiting
def func(lst, n, condition):
n_consec = 0
if len(lst) < n:
return (False, None)
for i,sub in enumerate(lst):
if condition(sub):
n_consec += 1
if n_consec == n:
return (True, (i-n+1, i))
else:
n_consec = 0
if len(lst) - (i + 1) < n:
return (False, None)
return (False, None)
print(func(lst,n, lambda sub: len(sub) >= n))
Allows setting different conditionals
def check(lst, conditional, n):
" Checks for consective sublist satisfying conditional "
for i in range(len(lst)):
# Starting with i-th sublist
for j in range(i, i+n):
# checking for n consecutive sublists
# where conditional(lst[j]) is True
if not conditional(lst[j]):
break
else:
return True, i, i+n-1
return False
def condition(sublist):
" Condiiton on length "
return len(sublist) >= 3
lst = [[1,2,3],[6,7,8],[4,5,6],[1,3,4,5]]
print(check(lst, condition, 3))
# Out: (True, 0, 2)
lst = [[1,2,3],[6,7,8],[4,5,6],[1,3,4,5]]
def check_cond_func(lst, n):
count = 0
range = []
for i, l in enumerate(lst):
if count == n:
break
if len(l) != n:
count = 0
if len(l) == n:
count += 1
range.append(i)
if count == n:
return (True, (min(range), max(range)))
else:
return False
yay_nay, index_range = check_cond_func(lst, 3)
print(yay_nay)
print(index_range)
Output
True
(0, 2)

Python: check if a list can be sorted by swapping two elements, only one swap is allowed

Here in below code, I'm trying to find out if there are two elements in left side which are greater than right side element but this doesn't seem to work for my problem. Any hints to write further logic? I'm stuck here.
swap.py
def swap(lst):
count = 0
for k in range(0, len(lst)-1):
if lst[k] > lst[k+1]:
count += 1
if int(count) == 2:
print "Swapped"
elif int(count) == 0:
print True
else:
print False
if __name__ == "__main__":
swap([1,2,3,4,0])
swap([6,4,2,5])
swap([6,4,2,8])
swap([1,4,5])
My expected output from program -
[1,4,5] will return True
[6,4,2,8] will return Swapped
[6,4,2,5] will return False
from itertools import combinations
def is_swappable(lst):
s = sorted(lst)
for i, j in combinations(range(len(lst)), 2):
l = lst[:]
l[i], l[j] = l[j], l[i]
if l == s:
return True
return False
Here's a pretty naive solution. Tries swapping every pair in the list and sees if that results in the sorted list.
I did not understand the "swapped" condition but the following code snipped will tell you if you can sort an array in one swap or not.
Code is written in Python 3 and the complexity of this code is O(nlog(n))
def checkOneSwap(arr):
N = len(arr)
if N <= 2:
print(True)
arr2 = []
for index in range(N):
arr2.append(arr[index])
arr2.sort()
counter = 0
for i in range(N):
if arr[i] != arr2[i]:
counter += 1
if counter == 0 or counter == 2:
print(True)
else:
print(False)
checkOneSwap([1,2,3,4,0]) # False you definetly need for than 2 swap to make this array sorted
checkOneSwap([6,4,2,5]) # False [2,4,5,6] -> swap(6,2) and then swap(6,5) require 2 swap to make this array sorted
checkOneSwap([6,4,2,8]) # True [2,4,6,8] -> swap(6,2), one swap required to make this array sorted
checkOneSwap([1,4,5]) # True [1,4,5] -> already sorted,counter = 0
Can be done with for loop, but I prefer list comprehension. Zip sorted and unsorted list and create a list of mismatches. If the length of mismatches is more than 2, then you can't sort in 1 swap.
def is_sortable_by_one_swap(unsorted_list):
mismatches = [x for x in zip(unsorted_list, sorted(unsorted_list)) if x[0] != x[1]]
return len(mismatches) <= 2

I am trying to make a function which return max from nested list?

I wrote this and its working fine with everything but when I have an empty list
in a given list(given_list=[[],1,2,3]) it saying index is out of range. Any help?
def r_max (given_list):
largest = given_list[0]
while type(largest) == type([]):
largest = largest[0]
for element in given_list:
if type(element) == type([]):
max_of_elem = r_max(element)
if largest < max_of_elem:
largest = max_of_elem
else: # element is not a list
if largest < element:
largest = element
return largest
You are assuming given_list has at least 1 element which is incorrect.
To avoid index out of range, you may add
if (len(given_list) == 0)
return None
to the beginning of your function.
that error indicates your index is out of range, which is the case with the first element of your example. The solution is not to iterate over lists of length zero:
def r_max (given_list):
largest = given_list[0]
while type(largest) == type([]):
largest = largest[0]
for element in given_list:
if type(element) == type([]):
# If the list is empty, skip
if(len(elemnt) == 0)
next
max_of_elem = r_max(element)
if largest < max_of_elem:
largest = max_of_elem
else: # element is not a list
if largest < element:
largest = element
return larges
while your at it, you might want to assert len(given_list)>0 or something equivalent.
If the nesting is arbitrarily deep, you first need recursion to untangle it:
def items(x):
if isinstance(x, list):
for it in x:
for y in items(it): yield y
else: yield x
Now, max(items(whatever)) will work fine.
In recent releases of Python 3 you can make this more elegant by changing
for it in x:
for y in items(x): yield y
into:
for it in x: yield from it
If you're confident that there will only be one level of nesting in there, you could do something like
def r_max(lst):
new_lst = []
for i in lst:
try:
new_lst.extend(i)
except TypeError:
new_lst + [i]
return max(new_lst)
But I'm not in love with that solution - but it might inspire you to come up with something nicer.
Two things I'd like to highlight about this solution, in contrast to yours:
All the type-checking you're doing (type(largest) == type([]), etc.) isn't considered idiomatic Python. It works, but one of the key points of Python is that it promotes duck typing/EAFP, which means that you should be more concerned with what an object can do (as opposed to what type it is), and that you should just try stuff and recover as opposed to figuring out if you can do it.
Python has a perfectly good "find the largest number in a list" function - max. If you can make your input a non-nested list, then max does the rest for you.
This will find the maximum in a list which contains nested lists and ignore string instances.
A = [2, 4, 6, 8, [[11, 585, "tu"], 100, [9, 7]], 5, 3, "ccc", 1]
def M(L):
# If list is empty, return nothing
if len(L) == 0:
return
# If the list size is one, it could be one element or a list
if len(L) == 1:
# If it's a list, get the maximum out of it
if isinstance(L[0], list):
return M(L[0])
# If it's a string, ignore it
if isinstance(L[0], str):
return
# Else return the value
else:
return L[0]
# If the list has more elements, find the maximum
else:
return max(M(L[:1]), M(L[1:]))
print A
print M(A)
Padmal's BLOG
I assume that the max element of an empty list is negative infinity.
This assumption will deal with the cases like [], [1,2,[],5,4,[]]
def find_max(L):
if len(L) == 0:
return float("-inf")
elif len(L) == 1:
if isinstance(L[0], list):
return find_max(L[0])
else:
return L[0]
elif len(L) == 2:
if isinstance(L[0], list):
firstMax = find_max(L[0])
else:
firstMax = L[0]
if isinstance(L[1], list):
lastMax = find_max(L[1])
else:
lastMax = L[1]
if firstMax > lastMax:
return firstMax
else:
return lastMax
else:
if isinstance(L[0], list):
firstMax = find_max(L[0])
lastMax = find_max(L[1:])
if firstMax > lastMax:
return firstMax
else:
return lastMax
else:
lastMax = find_max(L[1:])
if L[0] > lastMax:
return L[0]
else:
return lastMax

Python: Most efficient way to compare two lists of integers

I'm trying to compare two lists of integers, each the same size, in Python 2.6. The comparison I need is to compare the first item in List 1 with the first item in List 2, the second item in List 1 with the second item in List 2, and so on, and returns a result if ALL of the list items follow the same comparison criteria. It should behave as follows:
list1 = [1,1,1,1]
list2 = [2,1,2,3]
compare(list1,list2)
# returns a "list 1 is <= list 2" response.
list1 = [4,1,4,3]
list2 = [2,1,2,3]
compare(list1,list2)
# returns a "list 1 is >= list 2" response.
list1 = [3,2,3,2]
list2 = [1,4,1,4]
compare(list1,list2)
# returns None— some items in list1 > list2, and some items in list2 > list1.
I figured I could write the code like the following block, but I don't know if it's the most efficient. My program is going to be calling this method a LOT so I want to streamline this as much as possible.
def compare(list1,list2):
gt_found = 0
lt_found = 0
for x in range(len(list1)):
if list1[x] > list2[x]:
gt_found += 1
elif list1[x] < list2[x]:
lt_found += 1
if gt_found > 0 and lt_found > 0:
return None #(some items >, some items <)
if gt_found > 0:
return 1 #(list1 >= list2)
if lt_found > 0:
return -1 #(list1 <= list2)
return 0 #(list1 == list2)
Is it already as good as it's going to get (big-O of n), or is there a faster way to go about it (or a way that uses system functions instead)?
CLARIFICATION: I expect the case that returns 'None' to happen the most often, so it is important.
You can consider a numpy-based vectorized comparison.
import numpy as np
a = [1,1,1,2]
b = [2,2,4,3]
all_larger = np.all(np.asarray(b) > np.asarray(a)) # true if b > a holds elementwise
print all_larger
True
Clearly, you can engineer the thing to have your answer.
all_larger = lambda b,a : np.all(np.asarray(b) > np.asarray(a))
if all_larger(b,a):
print "b > a"
elif all_larger(a,b):
print "a > b"
else
print "nothing!"
Every type of comparison such as <, >, <=, >=, can be done.
Are you familiar with the wonderful zip function?
import itertools
def compare(xs, ys):
all_less = True
all_greater = True
for x, y in itertools.izip(xs, ys):
if not all_less and not all_greater:
return None
if x > y:
all_less = False
elif x < y:
all_greater = False
if all_less:
return "list 1 is <= list 2"
elif all_greater:
return "list 1 is >= list 2"
return None # all_greater might be set False on final iteration
Zip takes two lists (xs and ys in this case, but call them whatever you want) and creates an iterator for a sequence of tuples.
izip([1,2,3,4], [4,3,2,1]) == [(1,4), (2,3), (3,2), (4,1)]
This way you can iterate through both lists simultaneously and compare each value in tandem. The time complexity should be O(n), where n is the size of your lists.
It will return early in cases where neither the >= or <= condition are met.
Update
As James Matta points out, itertools.izip performs better than the standard zip in Python 2. This isn't true in Python 3, where the standard zip works the way izip does in older versions.
For anyone interested in the performance of the two methods, I named the iterative method 'tortoise' and the numpy method 'hare', and tested it with the code below.
At first, the 'tortoise' won [.009s [T] vs .033s [H]], but I checked it and found that asarray() was being called more often than it need to be. With that fix, the 'hare' won again, [.009s [T] vs .006s [H]].
The data is here: http://tny.cz/64d6e5dc
It consists of 28 lines of about 950 elements in length. Four of the lines collectively >= all the others.
It might be interesting to see how the performance works on larger data sets.
import itertools, operator, math
import cProfile
import numpy as np
data = #SEE PASTEBIN
def tortoise(xs, ys):
all_less = True
all_greater = True
for x, y in zip(xs, ys):
if not all_less and not all_greater:
return None
if x > y:
all_less = False
elif x < y:
all_greater = False
if all_greater and all_less:
return 0
if all_greater:
return 1
if all_less:
return -1
return None # all_greater might be set False on final iteration
hare = lambda b,a : np.all(b >= a)
def find_uniques_tortoise():
include_list = range(len(data))
current_list_index = 0
while current_list_index < len(data):
if current_list_index not in include_list:
current_list_index += 1
continue
for x in range(current_list_index+1,len(data)):
if x not in include_list:
continue
result = tortoise(data[current_list_index], data[x])
if result is None: #no comparison
continue
elif result == 1 or result == 0: # this one beats the other one
include_list.remove(x)
continue
elif result == -1: #the other one beats this one
include_list.remove(current_list_index)
break
current_list_index +=1
return include_list
def find_uniques_hare():
include_list = range(len(data))
current_list_index = 0
#do all asarray()s beforehand for max efficiency
for x in range(len(data)):
data[x] = np.asarray(data[x])
while current_list_index < len(data):
if current_list_index not in include_list:
current_list_index += 1
continue
for x in range(current_list_index+1,len(data)):
if x not in include_list:
continue
if hare(data[current_list_index], data[x]): # this one beats the other one, or it's a tie
include_list.remove(x)
# print x
continue
elif hare(data[x], data[current_list_index]): #the other one beats this one
include_list.remove(current_list_index)
# print current_list_index
break
else: #no comparison
continue
current_list_index +=1
return include_list
cProfile.run('find_uniques_tortoise()')
cProfile.run('find_uniques_hare()')
print find_uniques_tortoise()
print
print find_uniques_hare()

Categories

Resources