确定列表是否按降序排列

use*_*420 11 python

我正在尝试编写一个函数来测试列表是否按降序排列.这是我到目前为止所做的,但它似乎并不适用于所有列表.

我使用了列表[9,8,5,1,4,3,2]并返回了'true'.

我似乎无法弄清楚我的错误在哪里.

def ordertest(A):
    n = len(A)
    for i in range(n):
        if A[i] >= A[i+1]:
            return 'true'
        else:
            return 'false'
Run Code Online (Sandbox Code Playgroud)

Gar*_*tty 30

你可以很容易地做到这一点发电机的表达all()内置:

all(earlier >= later for earlier, later in zip(seq, seq[1:]))
Run Code Online (Sandbox Code Playgroud)

例如:

>>> seq = [9, 8, 5, 1, 4, 3, 2] 
>>> all(earlier >= later for earlier, later in zip(seq, seq[1:]))
False
>>> seq = [9, 8, 5, 4, 3, 2] 
>>> all(earlier >= later for earlier, later in zip(seq, seq[1:]))
True
Run Code Online (Sandbox Code Playgroud)

这应该是好的和快速的,因为它避免了python端循环,很好地短路(如果你itertools.izip()在2.x中使用),并且很好,清晰和可读(例如,避免循环索引).

请注意,所有迭代器(不仅仅是序列)的通用解决方案也是可行的:

first, second = itertools.tee(iterable)
next(second)
all(earlier >= later for earlier, later in zip(first, second))
Run Code Online (Sandbox Code Playgroud)


Roh*_*ain 11

你应该反向检查(一旦你得到A[i] < A[i+1],返回false

def ordertest(A):
    for i in range( len(A) - 1 ):
        if A[i] < A[i+1]:
            return False
        return True
Run Code Online (Sandbox Code Playgroud)

  • 通过索引访问进行迭代感觉真的是非语音(更不用说可能很慢). (2认同)

zig*_*igg 5

我最初建议使用sorted,并向我指出它可能不如你的迭代效率低.

>>> l = [3, 1, 2]
>>> l == sorted(l, reverse=True)
False
>>> l = [3, 2, 1]
>>> l == sorted(l, reverse=True)
True
Run Code Online (Sandbox Code Playgroud)

所以我对接受的答案进行了基准测试,我的,Lattyware的发电机解决方案,以及相同的itertools.izip.我故意使用了一个我认为有利于我的sorted解决方案的案例:一个最终只是无序的列表.这些基准测试是在旧的OpenBSD机器上的Python 2.7.1上执行的.

sorted.py

import time
l = list(reversed(range(99998) + [99999, 99998]))
start = time.time()
for count in range(100):
    l == sorted(l)
end = time.time()
print('elapsed: {}'.format(end - start))
Run Code Online (Sandbox Code Playgroud)

walk.py

import time
def ordertest(l):
    for i in range(len(l) - 1):
        if l[i] < l[i+1]:
            return False
    return True
l = list(reversed(range(99998) + [99999, 99998]))
start = time.time()
for count in range(100):
    ordertest(l)
end = time.time()
print('elapsed: {}'.format(end - start))
Run Code Online (Sandbox Code Playgroud)

generator.py

import time
l = list(reversed(range(99998) + [99999, 99998]))
start = time.time()
for count in range(100):
    all(earlier >= later for earlier, later in zip(l, l[1:]))
end = time.time()
print('elapsed: {}'.format(end - start))
Run Code Online (Sandbox Code Playgroud)

izip.py

import itertools
import time
l = list(reversed(range(99998) + [99999, 99998]))
start = time.time()
for count in range(100):
    all(earlier >= later for earlier, later in itertools.izip(l, l[1:]))
end = time.time()
print('elapsed: {}'.format(end - start))
Run Code Online (Sandbox Code Playgroud)

结果:

$ python sorted.py
elapsed: 1.0896859169
$ python walk.py
elapsed: 0.641126155853
$ python generator.py
elapsed: 4.79061508179
$ python izip.py
elapsed: 0.363445997238
Run Code Online (Sandbox Code Playgroud)

正如对此答案的评论中所指出的,通过zip制作列表的副本,生成器表达式可能会变慢.使用izip节拍.

  • 这没有特别的原因浪费了大量的CPU时间 - 特别是有很长的列表. (4认同)
  • 只要任何元素大于其前身,`for`循环就可以提前保释.即使`sorted`使用了一个堆(它没有使用它,你仍然会看O(N*log(N))运行时,而对于简单的`for`循环则需要O(N),这使得它更慢常见的情况. (3认同)

phi*_*hag 5

您可以迭代输入,而不是使用索引:

def ordertest(iterable):
    it = iter(iterable)
    prev = next(it)
    for e in it:
        if e > prev:
            return False
        prev = e
    return True
Run Code Online (Sandbox Code Playgroud)

请注意,这是一个坏主意,返回字符串'true''false'.相反,您可以使用Python的内置布尔值.


And*_*ark 5

以下是执行此测试的简明方法all():

def ordertest(A):
    return all(A[i] >= A[i+1] for i in range(len(A)-1))
Run Code Online (Sandbox Code Playgroud)

例子:

>>> ordertest([9,8,5,1,4,3,2])
False
>>> ordertest([9,8,5,4,3,2,1])
True
Run Code Online (Sandbox Code Playgroud)

  • 循环索引并不是非常pythonic. (3认同)
  • 非常好且易于理解的oneliner。如果 Pythonicity 快速且易于理解,谁会关心它。 (2认同)