代码之家  ›  专栏  ›  技术社区  ›  anijhaw

检查列表是否已排序的Pythonic方法

  •  114
  • anijhaw  · 技术社区  · 14 年前

    有没有一个pythonic方法来检查一个列表是否已经被排序了 ASC DESC

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

    像这样的 isttimestamps.isSorted() True False

    20 回复  |  直到 8 年前
        1
  •  225
  •   Andreas Haferburg    7 年前

    实际上我们并没有给出anijhaw想要的答案。这是一行:

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

    对于Python 3:

    all(l[i] <= l[i+1] for i in range(len(l)-1))
    
        2
  •  86
  •   dimo414    8 年前

    我只想用

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

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

    如果你只是要排序,如果它没有排序,那么忘记检查和排序。

    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)(并且O(n)在 for 回过头来!)所以,除非你期望它在大多数时候都不会被排序(而且是随机的),否则我还是会对列表进行排序。

        3
  •  46
  •   maksim Tiago    6 年前

    此迭代器形式比使用整数索引快10-15%:

    # python2 only
    if str is bytes:
        from itertools import izip as zip
    
    def is_sorted(l):
        return all(a <= b for a, b in zip(l, l[1:]))
    
        4
  •  22
  •   Alexandre Vassalotti    11 年前

    实现这一点的一个很好的方法是使用 imap 函数来自 itertools

    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))
    

    这种实现速度很快,适用于任何iterables。

        5
  •  11
  •   Nathan Farrington    14 年前

    我做了个基准测试 sorted(lst, reverse=True) == lst 是长名单中最快的,而且 all(l[i] >= l[i+1] for i in xrange(len(l)-1)) 是最快的短名单 . 这些基准测试运行在MacBookPro 2010 13“(Core2 Duo 2.66GHz,4GB1067MHz DDR3 RAM,MacOSX10.6.5)上。

    • 所有(l[i]>=l[i+1],对于x范围内的i(len(l)-1))
    • 最适合长排序列表: sorted(l, reverse=True) == l
    • 所有(l[i]>=l[i+1],对于x范围内的i(len(l)-1))

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

    更新: 阿伦斯特林的答案(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
    
        6
  •  9
  •   banbh    10 年前

    我会这么做(从这里的很多答案(亚伦·斯特林,惠业东,保罗·麦奎尔的一部分)中偷来)而且大部分都是这样 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))
    

        7
  •  5
  •   Martin Spacek    12 年前

    我用这一行基于微小差异():

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

    但是,如果x是无符号int,则需要小心,这可能会导致中的静默整数下溢微小差异(),导致假阳性。以下是修改后的版本:

    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()
    
        8
  •  4
  •   timgeb    9 年前

    lst ,您可以生成
    (item, next_item) zip :

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

    在Python3中, 拉链 已经返回了一个生成器,在python2中可以使用 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
    

    一定要使用 itertools.izip文件 在这里,如果您使用的是python2,否则就不必从生成器创建列表。

        9
  •  3
  •   Wai Yip Tung    14 年前

    蓝宝石太阳 lst.sort()

        10
  •  3
  •   Anthon    12 年前

    虽然我不认为有一个保证 sorted 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])
    

    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
    
        11
  •  3
  •   orlade    12 年前

    一点都不太像蟒蛇,但我们至少需要一个 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')
    

    accumulator变量只存储上次检查的值,如果任何值小于前一个值,则将累加器设置为无穷大(因此最后仍然是无穷大,因为“前一个值”始终大于当前值)。

        12
  •  2
  •   Amit Moscovich    12 年前

    返回(排序(lst)==lst)

    如果大部分时间数组没有排序,那么最好使用一种解决方案,该解决方案不扫描整个数组,并且在发现未排序的前缀时立即返回False。下面是我能找到的最快的解决方案,它不是特别优雅:

    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
    

    使用nathanfarrington的基准测试,除了在大的排序列表上运行外,在所有情况下,这都比使用sorted(lst)实现更好的运行时。

    这是我电脑上的基准测试结果。

    • L1:1.23838591576
    • 三级:1.17996287346
    • L4:4.68399500847

    第二种解决方案:

    • 三级:1.06135106087
    • L4:8.82761001587
        13
  •  2
  •   tal    8 年前

    如果您想用最快的方式来实现numpy阵列,请使用 numba

    代码将很快,因为它将由numba编译

    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
    
        14
  •  2
  •   MSeifert    8 年前

    只需添加另一种方式(即使它需要额外的模块): 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
    

    要检查描述顺序:

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

    strict

    对你来说这不是问题但是 你的序列包含 nan 值,则某些方法将失败,例如使用排序的:

    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
    

    请注意 迭代_实用程序。所有的都是单调的 与这里提到的其他解决方案相比,执行速度更快,特别是对于未排序的输入(请参阅 benchmark ).

        15
  •  2
  •   Sergey11g    6 年前

    懒惰的

    from itertools import tee
    
    def is_sorted(l):
        l1, l2 = tee(l)
        next(l2, None)
        return all(a <= b for a, b in zip(l1, l2))
    
        16
  •  2
  •   Chweng Mega    6 年前

    from more_itertools import pairwise
    
    class AssertionHelper:
        @classmethod
        def is_ascending(cls, data: iter) -> bool:
            for a, b in pairwise(data):
                if a > b:
                    return False
            return True
    
        @classmethod
        def is_descending(cls, data: iter) -> bool:
            for a, b in pairwise(data):
                if a < b:
                    return False
            return True
    
        @classmethod
        def is_sorted(cls, data: iter) -> bool:
            return cls.is_ascending(data) or cls.is_descending(data)
    
    >>> AssertionHelper.is_descending((1, 2, 3, 4))
    False
    >>> AssertionHelper.is_ascending((1, 2, 3, 4))
    True
    >>> AssertionHelper.is_sorted((1, 2, 3, 4))
    True
    
    
        17
  •  1
  •   FBruzzesi    5 年前

    因为我没有看到这个选项上面,我会把它添加到所有的答案。 让我们用 l ,然后:

    import numpy as np
    
    # Trasform the list to a numpy array
    x = np.array(l)
    
    # check if ascendent sorted:
    all(x[:-1] <= x[1:])
    
    # check if descendent sorted:
    all(x[:-1] >= x[1:])
    
        18
  •  1
  •   Xavier Guihot    4 年前

    随着即将到来的 Python 3.10 release schedule pairwise 函数提供了一种在连续元素对之间滑动的方法,从而确定是否所有这些对都满足相同的排序谓词:

    from itertools import pairwise
    
    all(x <= y for x, y in pairwise([1, 2, 3, 5, 6, 7]))
    # True
    

    两两 :

    pairwise([1, 2, 3, 5, 6, 7])
    # [(1, 2), (2, 3), (3, 5), (5, 6), (6, 7)]
    
        19
  •  1
  •   Zane Dufour    4 年前

    more_itertools.is_sorted

    我不确定这是什么时候添加的,但还没有提到:

    import more_itertools
    
    ls = [1, 4, 2]
    
    print(more_itertools.is_sorted(ls))
    
    ls2 = ["ab", "c", "def"]
    
    print(more_itertools.is_sorted(ls2, key=len))
    
        20
  •  0
  •   Mr Weasel    5 年前
    from functools import reduce
    
    # myiterable can be of any iterable type (including list)
    isSorted = reduce(lambda r, e: (r[0] and (r[1] or r[2] <= e), False, e), myiterable, (True, True, None))[0]
    

    导出的归约值是由三部分组成的元组( 分类标签 , , LastElement值 True , 是的 , None ),也用作空列表的结果(由于没有无序元素,因此被视为已排序)。在处理每个元素时,它会计算元组的新值(使用上一个元组值和下一个elementValue):

    [0] (sortedSoFarFlag) evaluates true if: prev_0 is true and (prev_1 is true or prev_2 <= elementValue)
    [1] (firstTimeFlag): False
    [2] (lastElementValue): elementValue
    

    [0]: True/False depending on whether the entire list was in sorted order
    [1]: True/False depending on whether the list was empty
    [2]: the last element value
    

    第一个值是我们感兴趣的值,所以我们使用 [0]

        21
  •  0
  •   PaulMcG    5 年前

    使用赋值表达式的解决方案(在Python 3.8中添加):

    def is_sorted(seq):
        seq_iter = iter(seq)
        cur = next(seq_iter, None)
        return all((prev := cur) <= (cur := nxt) for nxt in seq_iter)
    
    z = list(range(10))
    print(z)
    print(is_sorted(z))
    
    import random
    random.shuffle(z)
    print(z)
    print(is_sorted(z))
    
    z = []
    print(z)
    print(is_sorted(z))
    

    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    True
    [1, 7, 5, 9, 4, 0, 8, 3, 2, 6]
    False
    []
    True
    
        22
  •  -1
  •   Community CDub    4 年前

    这实际上是使用递归实现的最短方法:

    如果已排序,则将打印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)
    
        23
  •  -1
  •   Zuckerberg    7 年前

    def is_list_sorted(al):
    
        llength =len(al)
    
    
        for i in range (llength):
            if (al[i-1] > al[i]):
                print(al[i])
                print(al[i+1])
                print('Not sorted')
                return -1
    
        else :
            print('sorted')
            return  true
    
        24
  •  -1
  •   Aluis92    6 年前

    最简单的方法:

    def isSorted(arr):
      i = 1
      while i < len(arr):
        if(result[i] < result[i - 1]):
          return False
        i += 1
      return True
    
        25
  •  -3
  •   prodev_paris    9 年前

    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.')
    

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

    另一种查找给定列表是否已排序的方法

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