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

发布于 2024-09-24 09:01:11 字数 268 浏览 11 评论 0原文

是否有一种Python式的方法来检查列表是否已按 ASCDESC 排序,

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

例如返回 isttimestamps.isSorted() TrueFalse

我想输入一些消息的时间戳列表,并检查事务是否以正确的顺序出现。

Is there a pythonic way to check if a list is already sorted in ASC or DESC

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

something like isttimestamps.isSorted() that returns True or False.

I want to input a list of timestamps for some messages and check if the the transactions appeared in the correct order.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(27

心病无药医 2024-10-01 09:01:12

第三方封装方法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))

The third-party package method more_itertools.is_sorted hasn't been mentioned yet:

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))
一片旧的回忆 2024-10-01 09:01:12

我使用这个基于 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()

I use this one-liner based on numpy.diff():

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

I haven't really timed it against any other method, but I assume it's faster than any pure Python method, especially for large n, since the loop in numpy.diff (probably) runs directly in C (n-1 subtractions followed by n-1 comparisons).

However, you need to be careful if x is an unsigned int, which might cause silent integer underflow in numpy.diff(), resulting in a false positive. Here's a modified version:

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()
生生漫 2024-10-01 09:01:12

这与最上面的答案类似,但我更喜欢它,因为它避免了显式索引。假设您的列表的名称为 lst,您可以使用 zip 从列表中生成
(item, next_item) 元组:

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,否则您将无法实现不必从生成器创建列表的目的。

This is similar to the top answer, but I like it better because it avoids explicit indexing. Assuming your list has the name lst, you can generate
(item, next_item) tuples from your list with zip:

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

In Python 3, zip already returns a generator, in Python 2 you can use itertools.izip for better memory efficiency.

Small demo:

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

The last one fails when the tuple (3, 2) is evaluated.

Bonus: checking finite (!) generators which cannot be indexed:

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

Make sure to use itertools.izip here if you are using Python 2, otherwise you would defeat the purpose of not having to create lists from the generators.

深陷 2024-10-01 09:01:12

懒惰的

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

Lazy

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))
知足的幸福 2024-10-01 09:01:12

虽然我认为不能保证 sorted 内置函数使用 i+1, i 调用其 cmp 函数,但对于 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

Although I don't think there is a guarantee for that the sorted built-in calls its cmp function with i+1, i, it does seem to do so for CPython.

So you could do something like:

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

Or this way (without if statements -> EAFP gone wrong? ;-) ):

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
失退 2024-10-01 09:01:12

正如 @aaronsterling 所指出的,当数组已排序且不太小时,以下解决方案是最短的并且似乎最快:
def is_sorted(lst):
return (sorted(lst) == lst)

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

def is_sorted(lst):
    it = iter(lst)
    try:
        prev = next(it)
    except StopIteration:
        return True
    for x in it:
        if prev > x:  # For reverse, use <
            return False
        prev = x
    return True

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

这是我的计算机上的基准测试结果。

排序(lst)==lst解决方案

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

第二个解决方案:

  • L1:0.81095790863
  • L2:0.80239 7012711
  • L3:1.06135106087
  • L4:8.82761001587

As noted by @aaronsterling the following solution is the shortest and seems fastest when the array is sorted and not too small:
def is_sorted(lst):
return (sorted(lst) == lst)

If most of the time the array is not sorted, it would be desirable to use a solution that does not scan the entire array and returns False as soon as an unsorted prefix is discovered. Following is the fastest solution I could find, it is not particularly elegant:

def is_sorted(lst):
    it = iter(lst)
    try:
        prev = next(it)
    except StopIteration:
        return True
    for x in it:
        if prev > x:  # For reverse, use <
            return False
        prev = x
    return True

Using Nathan Farrington's benchmark, this achieves better runtime than using sorted(lst) in all cases except when running on the large sorted list.

Here are the benchmark results on my computer.

sorted(lst)==lst solution

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

Second solution:

  • L1: 0.81095790863
  • L2: 0.802397012711
  • L3: 1.06135106087
  • L4: 8.82761001587
残花月 2024-10-01 09:01:12

只是添加另一种方式(即使它需要额外的模块): < code>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值,那么某些方法将失败,例如排序:

def is_sorted_using_sorted(iterable):
    return sorted(iterable) == iterable

>>> is_sorted_using_sorted([3, float('nan'), 1])  # definitely False, right?
True

>>> all_monotone([3, float('nan'), 1])
False

请注意iteration_utilities.all_monotone 与此处提到的其他解决方案相比执行速度更快,特别是未排序的输入(请参阅基准)。

Just to add another way (even if it requires an additional module): 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

To check for DESC order:

>>> all_monotone(listtimestamps, decreasing=True)
False

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

There is also a strict parameter if you need to check for strictly (if successive elements should not be equal) monotonic sequences.

It's not a problem in your case but if your sequences contains nan values then some methods will fail, for example with sorted:

def is_sorted_using_sorted(iterable):
    return sorted(iterable) == iterable

>>> is_sorted_using_sorted([3, float('nan'), 1])  # definitely False, right?
True

>>> all_monotone([3, float('nan'), 1])
False

Note that iteration_utilities.all_monotone performs faster compared to the other solutions mentioned here especially for unsorted inputs (see benchmark).

梦情居士 2024-10-01 09:01:12

一点也不 Pythonic,但我们至少需要一个 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')

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

Not very Pythonic at all, but we need at least one reduce() answer, right?

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

The accumulator variable simply stores that last-checked value, and if any value is smaller than the previous value, the accumulator is set to infinity (and thus will still be infinity at the end, since the 'previous value' will always be bigger than the current one).

夜还是长夜 2024-10-01 09:01:12

这种使用 Pandas 的方法非常慢,但它以完整性着称。

from typing import Sequence

import pandas as pd

def is_sorted(seq: Sequence, reverse: bool = False) -> bool:
    index = pd.Index(seq)
    if reverse:
        return index.is_monotonic_decreasing
    return index.is_monotonic_increasing

This approach using Pandas is very slow, but it's noted for completeness.

from typing import Sequence

import pandas as pd

def is_sorted(seq: Sequence, reverse: bool = False) -> bool:
    index = pd.Index(seq)
    if reverse:
        return index.is_monotonic_decreasing
    return index.is_monotonic_increasing
笑梦风尘 2024-10-01 09:01:12

SapphireSun 说得很对。您只需使用lst.sort()即可。 Python 的排序实现 (TimSort) 检查列表是否已排序。如果是这样,sort() 将在线性时间内完成。听起来像是一种确保列表排序的 Python 方式;)

SapphireSun is quite right. You can just use lst.sort(). Python's sort implementation (TimSort) check if the list is already sorted. If so sort() will completed in linear time. Sounds like a Pythonic way to ensure a list is sorted ;)

格子衫的從容 2024-10-01 09:01:12

Python 3.6.8

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

Python 3.6.8

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

岛歌少女 2024-10-01 09:01:12

使用赋值表达式的解决方案(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

A solution using assignment expressions (added in 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))

Gives:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
True
[1, 7, 5, 9, 4, 0, 8, 3, 2, 6]
False
[]
True
深巷少女 2024-10-01 09:01:12

应该已经安装了

如果你想要最快的 numpy 数组方式,请使用 numba,如果你使用conda 代码会很快,因为它将由 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

If you want the fastest way for numpy arrays, use numba, which if you use conda should be already installed

The code will be fast because it will be compiled by 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

and then:

>>> issorted(array([4,9,100]))
>>> True
灯角 2024-10-01 09:01:12

这使用了递归:

 def is_sorted(lst):
    if len(lst) == 1:
       return True
    return lst[0] <= lst[1] and is_sorted(lst[1:])

 some_list = [1,2,3,4]
 print(is_sorted(some_list))

请注意,对于长序列,这将引发RuntimeError:超出最大递归深度

This uses recursion:

 def is_sorted(lst):
    if len(lst) == 1:
       return True
    return lst[0] <= lst[1] and is_sorted(lst[1:])

 some_list = [1,2,3,4]
 print(is_sorted(some_list))

Note that this will raise RuntimeError: maximum recursion depth exceeded for long sequences.

濫情▎り 2024-10-01 09:01:12

试试这个:

def is_sorted(arr) -> bool:
    for i in range(1, len(arr)):
        if arr[i] < arr[i - 1]:
            return False
    return True

Try this:

def is_sorted(arr) -> bool:
    for i in range(1, len(arr)):
        if arr[i] < arr[i - 1]:
            return False
    return True
甜警司 2024-10-01 09:01:12
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]

导出的缩减值是一个由 3 部分组成的元组(sortedSoFarFlagfirstTimeFlaglastElementValue)。它最初以 (True, True, None) 开头,它也用作空列表的结果(视为已排序,因为有没有乱序元素)。当它处理每个元素时,它会计算元组的新值(使用前一个元组值和下一个元素值):

[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

第一个值是我们感兴趣的值,因此我们使用 < code>[0] 从reduce结果中获取它。

该解决方案适用于任何可迭代的包含可以相互比较的元素类型。其中包括布尔列表(检查 False 值出现在 True 值之前)、数字列表、字符串列表(按字母顺序排列)、集合列表(子集出现在超集之前)等。

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]

The derived reduction value is a 3-part tuple of (sortedSoFarFlag, firstTimeFlag, lastElementValue). It initially starts with (True, True, None), which is also used as the result for an empty list (regarded as sorted because there are no out-of-order elements). As it processes each element it calculates new values for the tuple (using previous tuple values with the next 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

The final result of the reduction is a tuple of:

[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

The first value is the one we're interested in, so we use [0] to grab that from the reduce result.

This solution works for any iterable containing element types that can be compared with each other. That includes lists of boolean (checks the False values occur before the True values), lists of numbers, lists of strings (alphabetical order), lists of sets (subsets occur before supersets) etc.

梦里兽 2024-10-01 09:01:12

这个怎么样?简单明了。

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

How about this one ? Simple and straightforward.

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
往昔成烟 2024-10-01 09:01:12

最简单的方法:

def isSorted(arr):
  i = 1
  while i < len(arr):
    if(result[i] < result[i - 1]):
      return False
    i += 1
  return True

Simplest way:

def isSorted(arr):
  i = 1
  while i < len(arr):
    if(result[i] < result[i - 1]):
      return False
    i += 1
  return True
可可 2024-10-01 09:01:12

对于整数或字符串绝对适用于 Python 3 及更高版本:

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

Definitely works in Python 3 and above for integers or strings:

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

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

Another way of finding if the given list is sorted or not

trees1 = list ([1, 4, 5, 3, 2])
trees2 = list (trees1)
trees2.sort()
if trees1 == trees2:
    print ('trees1 is SORTED')
else:
    print ('Not sorted')
思念满溢 2024-10-01 09:01:11

这是一个简单的说明:

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

如果使用 Python 2,请使用 xrange 而不是 range

对于 reverse=True,请使用 >= 而不是 <=

Here is a one liner:

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

If using Python 2, use xrange instead of range.

For reverse=True, use >= instead of <=.

梦罢 2024-10-01 09:01:11

我只会使用,

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) (并且在 for 循环中为 O(n)!)所以,除非如果您希望它在大多数情况下不会被排序(并且相当随机),那么我会再次对列表进行排序。

I would just use

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

unless it's a very big list in which case you might want to create a custom function.

if you are just going to sort it if it's not sorted, then forget the check and sort it.

lst.sort()

and don't think about it too much.

if you want a custom function, you can do something like

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

This will be O(n) if the list is already sorted though (and O(n) in a for loop at that!) so, unless you expect it to be not sorted (and fairly random) most of the time, I would, again, just sort the list.

平安喜乐 2024-10-01 09:01:11

这种迭代器形式比使用整数索引快 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:]))

This iterator form is 10-15% faster than using integer indexing:

# 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:]))
玩世 2024-10-01 09:01:11

实现此目的的一个很好的方法是使用来自 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))

此实现速度很快并且适用于任何可迭代对象。

A beautiful way to implement this is to use the imap function from 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))

This implementation is fast and works on any iterables.

左岸枫 2024-10-01 09:01:11

Python 3.10 开始,新的 pairwise 函数提供了一种滑动连续元素对的方法,从而查找所有这些元素对是否满足相同的排序谓词:

from itertools import pairwise

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

pairwise:

pairwise([1, 2, 3, 5, 6, 7])
# [(1, 2), (2, 3), (3, 5), (5, 6), (6, 7)]

Starting in Python 3.10, the new pairwise function provides a way to slide through pairs of consecutive elements, and thus find if all of these pairs satisfy the same predicate of ordering:

from itertools import pairwise

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

The intermediate result of pairwise:

pairwise([1, 2, 3, 5, 6, 7])
# [(1, 2), (2, 3), (3, 5), (5, 6), (6, 7)]
不及他 2024-10-01 09:01:11

我会这样做(从这里窃取了很多答案[Aaron Sterling,Wai Yip Tung,有点来自Paul McGuire],大部分是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))

一件好事:您不必实现该系列的第二个可迭代(与列表切片不同)。

I'd do this (stealing from a lot of answers here [Aaron Sterling, Wai Yip Tung, sorta from Paul McGuire] and mostly 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))

One nice thing: you don't have to realize the second iterable for the series (unlike with a list slice).

梦晓ヶ微光ヅ倾城 2024-10-01 09:01:11

我运行了一个基准测试 sorted(lst, reverse=True) == lst 对于长列表来说是最快的,而 all(l[i] >= l[i+ 1] for i in xrange(len(l)-1)) 是短列​​表最快的。这些基准测试在 MacBook Pro 2010 13"(Core2 Duo 2.66GHz、4GB 1067MHz DDR3 RAM、Mac OS X 10.6.5)上运行。

更新:我修改了脚本,以便您可以直接在您自己的系统上运行它。此外,我添加了排序和未排序的输入。

  • 最适合短排序列表:all(l[i] >= l[i) +1] for i in xrange(len(l)-1))
  • 最适合长排序列表: sorted(l,verse=True) == l
  • 最适合短未排序列表: all(l[i] >= l[i+1] for i in xrange(len(l)-1))
  • 最适合长未排序列表:all(l[i] >= l[i+1] for i in xrange(len(l)-1))

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

更新: aaronasterling 的答案(#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

I ran a benchmark and sorted(lst, reverse=True) == lst was the fastest for long lists, and all(l[i] >= l[i+1] for i in xrange(len(l)-1)) was the fastest for short lists. These benchmarks were run on a MacBook Pro 2010 13" (Core2 Duo 2.66GHz, 4GB 1067MHz DDR3 RAM, Mac OS X 10.6.5).

UPDATE: I revised the script so that you can run it directly on your own system. The previous version had bugs. Also, I have added both sorted and unsorted inputs.

  • Best for short sorted lists: all(l[i] >= l[i+1] for i in xrange(len(l)-1))
  • Best for long sorted lists: sorted(l, reverse=True) == l
  • Best for short unsorted lists: all(l[i] >= l[i+1] for i in xrange(len(l)-1))
  • Best for long unsorted lists: all(l[i] >= l[i+1] for i in xrange(len(l)-1))

So in most cases there is a clear winner.

UPDATE: aaronasterling's answers (#6 and #7) are actually the fastest in all cases. #7 is the fastest because it doesn't have a layer of indirection to lookup the key.

#!/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
〃安静 2024-10-01 09:01:11

由于我在上面没有看到此选项,因此我会将其添加到所有答案中。
让用 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:])

As I don't see this option above I will add it to all the answers.
Let denote the list by l, then:

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:])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文