Pythonic的方式来检查列表是否sorting

有没有Python方法来检查列表是否已经sorting在ASCDESC

 listtimestamps = [1, 2, 3, 5, 6, 7] 

isttimestamps.isSorted()返回TrueFalse

我想input一些消息的时间戳列表,并检查交易是否以正确的顺序出现。

其实我们没有给出anijhaw正在寻找的答案。 这是一个class轮:

 all(l[i] <= l[i+1] for i in xrange(len(l)-1)) 

我只会用

 if sorted(lst) == lst: # code here 

除非这是一个非常大的列表,在这种情况下,您可能需要创build一个自定义函数。

如果你只是要sorting,如果它没有sorting,然后忘记检查和sorting。

 lst.sort() 

不要想太多。

如果你想要一个自定义函数,你可以做类似的事情

 def is_sorted(lst, key=lambda x: x): for i, el in enumerate(lst[1:]): if key(el) < key(lst[i]): # i is the index of the previous element return False return True 

这将是O(n),如果列表已经被sorting(而O(n)在for循环中),除非你期望它在大部分时间没有被sorting(并且相当随机),否则再次,只是对列表进行sorting。

这个迭代器forms比使用整数索引要快10-15%:

 # from itertools import izip as zip # python 2 only! def is_sorted(l): return all(a <= b for a, b in zip(l[:-1], l[1:])) 

一个美丽的方法来实现这个是使用itertoolsimap函数:

 from itertools import imap, tee import operator def is_sorted(iterable, compare=operator.le): a, b = tee(iterable) next(b, None) return all(imap(compare, a, b)) 

这个实现很快,适用于任何迭代。

我会这样做的(这里偷了很多答案[Aaron Sterling,伟业堂,保罗·麦奎尔],主要是Armin Ronacher ):

 from itertools import tee, izip def pairwise(iterable): a, b = tee(iterable) next(b, None) return izip(a, b) def is_sorted(iterable, key=lambda a, b: a <= b): return all(key(a, b) for a, b in pairwise(iterable)) 

一件好事:你不必为系列实现第二个迭代器(与列表片不同)。

我运行了一个基准testingsorted(lst, reverse=True) == lst是长列表中速度最快的, all(l[i] >= l[i+1] for i in xrange(len(l)-1))是短名单中最快的 。 这些基准testing是在MacBook Pro 2010 13“(Core2 Duo 2.66GHz,4GB 1067MHz DDR3 RAM,Mac OS X 10.6.5)上运行的。

更新:我修改了脚本,以便您可以直接在自己的系统上运行它。 以前的版本有错误。 另外,我添加了sorting和未sorting的input。

  • 适用all(l[i] >= l[i+1] for i in xrange(len(l)-1))
  • 最适合长sorting列表: sorted(l, reverse=True) == l
  • 对于all(l[i] >= l[i+1] for i in xrange(len(l)-1))
  • 最好的长sorting列表: all(l[i] >= l[i+1] for i in xrange(len(l)-1))

所以在大多数情况下,有一个明确的赢家。

更新: aaronsterling的答案(#6和#7)实际上是所有情况下最快的。 #7是最快的,因为它没有间接寻找密钥的层。

 #!/usr/bin/env python import itertools import time def benchmark(f, *args): t1 = time.time() for i in xrange(1000000): f(*args) t2 = time.time() return t2-t1 L1 = range(4, 0, -1) L2 = range(100, 0, -1) L3 = range(0, 4) L4 = range(0, 100) # 1. def isNonIncreasing(l, key=lambda x,y: x >= y): return all(key(l[i],l[i+1]) for i in xrange(len(l)-1)) print benchmark(isNonIncreasing, L1) # 2.47253704071 print benchmark(isNonIncreasing, L2) # 34.5398209095 print benchmark(isNonIncreasing, L3) # 2.1916718483 print benchmark(isNonIncreasing, L4) # 2.19576501846 # 2. def isNonIncreasing(l): return all(l[i] >= l[i+1] for i in xrange(len(l)-1)) print benchmark(isNonIncreasing, L1) # 1.86919999123 print benchmark(isNonIncreasing, L2) # 21.8603689671 print benchmark(isNonIncreasing, L3) # 1.95684289932 print benchmark(isNonIncreasing, L4) # 1.95272517204 # 3. def isNonIncreasing(l, key=lambda x,y: x >= y): return all(key(a,b) for (a,b) in itertools.izip(l[:-1],l[1:])) print benchmark(isNonIncreasing, L1) # 2.65468883514 print benchmark(isNonIncreasing, L2) # 29.7504849434 print benchmark(isNonIncreasing, L3) # 2.78062295914 print benchmark(isNonIncreasing, L4) # 3.73436689377 # 4. def isNonIncreasing(l): return all(a >= b for (a,b) in itertools.izip(l[:-1],l[1:])) print benchmark(isNonIncreasing, L1) # 2.06947803497 print benchmark(isNonIncreasing, L2) # 15.6351969242 print benchmark(isNonIncreasing, L3) # 2.45671010017 print benchmark(isNonIncreasing, L4) # 3.48461818695 # 5. def isNonIncreasing(l): return sorted(l, reverse=True) == l print benchmark(isNonIncreasing, L1) # 2.01579380035 print benchmark(isNonIncreasing, L2) # 5.44593787193 print benchmark(isNonIncreasing, L3) # 2.01813793182 print benchmark(isNonIncreasing, L4) # 4.97615599632 # 6. def isNonIncreasing(l, key=lambda x, y: x >= y): for i, el in enumerate(l[1:]): if key(el, l[i-1]): return False return True print benchmark(isNonIncreasing, L1) # 1.06842684746 print benchmark(isNonIncreasing, L2) # 1.67291283607 print benchmark(isNonIncreasing, L3) # 1.39491200447 print benchmark(isNonIncreasing, L4) # 1.80557894707 # 7. def isNonIncreasing(l): for i, el in enumerate(l[1:]): if el >= l[i-1]: return False return True print benchmark(isNonIncreasing, L1) # 0.883186101913 print benchmark(isNonIncreasing, L2) # 1.42852401733 print benchmark(isNonIncreasing, L3) # 1.09229516983 print benchmark(isNonIncreasing, L4) # 1.59502696991 

虽然我不认为有保证, sorted内置调用它的cmp函数与i+1, i似乎这样做CPython。

所以你可以做这样的事情:

 def my_cmp(x, y): cmpval = cmp(x, y) if cmpval < 0: raise ValueError return cmpval def is_sorted(lst): try: sorted(lst, cmp=my_cmp) return True except ValueError: return False print is_sorted([1,2,3,5,6,7]) print is_sorted([1,2,5,3,6,7]) 

或者这样(没有if语句 – > EAFP出错了;-)):

 def my_cmp(x, y): assert(x >= y) return -1 def is_sorted(lst): try: sorted(lst, cmp=my_cmp) return True except AssertionError: return False 

根本不是Pythonic,但我们至less需要一个reduce()答案,对吧?

 def is_sorted(iterable): prev_or_inf = lambda prev, i: i if prev <= i else float('inf') return reduce(prev_or_inf, iterable, float('-inf')) < float('inf') 

累加器variables只存储最后一次检查的值,如果任何值小于前一个值,则累加器被设置为无穷大(因此“最后一个值”将始终大于最终值)目前的一个)。

蓝gem太好了 。 你可以使用lst.sort() 。 Python的sorting实现(TimSort)检查列表是否已经sorting。 如果这样sort()将在线性时间内完成。 听起来像Pythonic的方式,以确保列表sorting;)

正如@aaronsterling指出的那样,下面的解决scheme是最短的,而且在数组sorting的时候似乎是最快的,而且不是太小:def is_sorted(lst):return(sorted(lst)== lst)

如果大部分时间数组未被sorting,那么最好使用一个不扫描整个数组的方法,只要发现未sorting的前缀,就返回False。 以下是我能find的最快的解决scheme,它不是特别优雅:

 def is_sorted(lst): it = iter(lst) try: prev = it.next() except StopIteration: return True for x in it: if prev > x: return False prev = x return True 

使用Nathan Farrington的基准testing,除了在大型的sorting列表上运行,在所有情况下,这都比使用sorting(lst)实现更好的运行时间。

以下是我的电脑上的基准testing结果。

sorting(第一)==第一解决scheme

  • L1:1.23838591576
  • L2:4.19063091278
  • L3:1.17996287346
  • L4:4.68399500847

解决scheme二

  • L1:0.81095790863
  • L2:0.802397012711
  • L3:1.06135106087
  • L4:8.82761001587

我使用这个基于numpy.diff()的单线程:

 def issorted(x): """Check if x is sorted""" return (numpy.diff(x) >= 0).all() # is diff between all consecutive entries >= 0? 

我没有真正的时间对其他任何方法,但我认为它比任何纯Python方法,特别是对于大n,因为numpy.diff(可能)中的循环直接运行在C(n-1减法,其次是n -1比较)。

但是,如果x是一个无符号整数,则需要小心,这可能会导致numpy.diff()中的整数下溢,从而导致误报。 这是一个修改的版本:

 def issorted(x): """Check if x is sorted""" try: if x.dtype.kind == 'u': # x is unsigned int array, risk of int underflow in np.diff x = numpy.int64(x) except AttributeError: pass # no dtype, not an array return (numpy.diff(x) >= 0).all() 

这与顶级答案类似,但我更喜欢它,因为它避免了显式索引。 假设你的列表有名字lst ,你可以生成
(item, next_item)元组从您的列表中zip

 all(x <= y for x,y in zip(lst, lst[1:])) 

在Python 3中, zip已经返回一个生成器,在Python 2中,可以使用itertools.izip来获得更好的内存效率。

小演示:

 >>> lst = [1, 2, 3, 4] >>> zip(lst, lst[1:]) [(1, 2), (2, 3), (3, 4)] >>> all(x <= y for x,y in zip(lst, lst[1:])) True >>> >>> lst = [1, 2, 3, 2] >>> zip(lst, lst[1:]) [(1, 2), (2, 3), (3, 2)] >>> all(x <= y for x,y in zip(lst, lst[1:])) False 

当元组(3, 2)被评估时,最后一个失败。

奖金:检查无法索引的有限(!)生成器:

 >>> def gen1(): ... yield 1 ... yield 2 ... yield 3 ... yield 4 ... >>> def gen2(): ... yield 1 ... yield 2 ... yield 4 ... yield 3 ... >>> g1_1 = gen1() >>> g1_2 = gen1() >>> next(g1_2) 1 >>> all(x <= y for x,y in zip(g1_1, g1_2)) True >>> >>> g2_1 = gen2() >>> g2_2 = gen2() >>> next(g2_2) 1 >>> all(x <= y for x,y in zip(g2_1, g2_2)) False 

如果您使用的是Python 2,请确保在这里使用itertools.izip ,否则您将无法从生成器中创build列表。

 def is_sorted(l): l2 = iter(l) next(l2, None) return all(a <= b for a, b in zip(l, l2)) 

这实际上是使用recursion来做到这一点的最简单的方法:

如果Sorted将打印True否则将打印False

  def is_Sorted(lst): if len(lst) == 1: return True return lst[0] <= lst[1] and is_Sorted(lst[1:]) any_list = [1,2,3,4] print is_Sorted(any_list) 

如果你想要numpy数组的最快方式,使用numba ,如果你使用conda,应该已经安装了

代码会很快,因为它会被编译

 import numba @numba.jit def issorted(vec, ascending=True): if len(vec) < 2: return True if ascending: for i in range(1, len(vec)): if vec[i-1] > vec[i]: return False return True else: for i in range(1, len(vec)): if vec[i-1] < vec[i]: return False return True 

接着:

 >>> issorted(array([4,9,100])) >>> True 

只是添加另一种方式(即使它需要一个额外的模块): iteration_utilities.all_monotone

 >>> from iteration_utilities import all_monotone >>> listtimestamps = [1, 2, 3, 5, 6, 7] >>> all_monotone(listtimestamps) True >>> all_monotone([1,2,1]) False 

检查DESC命令:

 >>> all_monotone(listtimestamps, decreasing=True) False >>> all_monotone([3,2,1], decreasing=True) True 

如果您需要严格检查(如果连续的元素不应该相等)单调序列,那么也有一个strict参数。

这不是一个问题,但如果你的序列包含nan值,那么一些方法将失败,例如sorting:

 def is_sorted_using_sorted(iterable): return sorted(iterable) == iterable >>> is_sorted_using_sorted([3, float('nan'), 1]) # definetly False, right? True >>> all_monotone([3, float('nan'), 1]) False 

请注意, iteration_utilities.all_monotone执行速度比其他解决scheme,特别是对于未分类的input(见基准 )。

在Python 3和以上的整数或string肯定工作:

 def tail(t): return t[:] letters = ['a', 'b', 'c', 'd', 'e'] rest = tail(letters) rest.sort() if letters == rest: print ('Given list is SORTED.') else: print ('List NOT Sorted.') 

================================================== ===================

另一种查找给定列表是否sorting的方法

 trees1 = list ([1, 4, 5, 3, 2]) trees2 = list (trees1) trees2.sort() if trees1 == trees2: print ('trees1 is SORTED') else: print ('Not sorted')