12

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

我使用了列表[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'
4

7 回答 7

32

您可以使用生成器表达式内置函数轻松完成all()操作:

all(earlier >= later for earlier, later in zip(seq, seq[1:]))

例如:

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

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

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

first, second = itertools.tee(iterable)
next(second)
all(earlier >= later for earlier, later in zip(first, second))
于 2012-10-04T19:12:16.697 回答
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
于 2012-10-04T19:11:19.527 回答
8

这是执行此测试的简洁方法,该方法使用all()

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

例子:

>>> ordertest([9,8,5,1,4,3,2])
False
>>> ordertest([9,8,5,4,3,2,1])
True
于 2012-10-04T19:24:53.773 回答
5

我最初建议 using sorted,有人向我指出它可能比您的迭代效率低。

>>> l = [3, 1, 2]
>>> l == sorted(l, reverse=True)
False
>>> l = [3, 2, 1]
>>> l == sorted(l, reverse=True)
True

所以我对接受的答案进行了基准测试,我的,Lattyware 的生成器解决方案,和itertools.izip. 我特意使用了一个我认为有利于我的sorted解决方案的案例:一个仅在最后无序的列表。这些基准测试是在旧 OpenBSD 机器上的 Python 2.7.1 上执行的。

排序的.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))

步行.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))

生成器.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))

压缩包

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

结果:

$ python sorted.py
elapsed: 1.0896859169
$ python walk.py
elapsed: 0.641126155853
$ python generator.py
elapsed: 4.79061508179
$ python izip.py
elapsed: 0.363445997238

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

于 2012-10-04T19:12:00.817 回答
5

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

def ordertest(iterable):
    it = iter(iterable)
    prev = next(it)
    for e in it:
        if e > prev:
            return False
        prev = e
    return True

请注意,返回字符串'true''false'. 相反,您可以使用 Python 的内置booleans

于 2012-10-04T19:13:34.980 回答
2

你想做的是

n=len(A)
for i in range(n - 1):
    if A[i]<=A[i+1]:
        return 'false'
return 'true

尝试在你的脑海中执行你的代码。在第一次迭代中,如果 A[i] 大于 A[i + 1] 则返回 true,否则返回 false。你永远不会在你的名单上走得更远。

好的解决方案是测试您的状况,如果随时为假,则返回假。但如果它是正确的,这并不意味着列表的其余部分是,并且您想要测试您的每个值。

当你测试 A[i + 1] 时,你不想在列表的末尾,而是在n - 1它的项目。

于 2012-10-04T19:11:44.670 回答
0
n=len(l)
c=0
for i in range(n - 1):
    if l[i]<l[i+1]:
        c+=1
    if c==1:
        break
if(c==1):
    return False
return True

要检查没有任何错误并检查是否太正确,最好使用计数器进行此功能。一旦循环运行并且迭代变为 1,它就不再需要搜索了。它将返回 false 否则为 true。谢谢!

于 2018-09-05T04:58:11.507 回答