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 側のループやショート サーキットを適切に回避し (2.x で使用する場合itertools.izip())、適切で明確で読みやすい (たとえば、インデックスのループを回避する) ため、高速である必要があります。

すべてのイテレータ (シーケンスだけでなく) に対する一般的な解決策も可能であることに注意してください。

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

私はもともと を使用することを提案しましたが、あなたの反復よりも効率が悪いかもしれないと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 で実行されました。

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

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

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

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

結果:

$ 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 を返します。あなたはあなたのリストでさらに進むことはありません.

適切な解決策は、条件をテストし、常に false の場合は false を返すことです。しかし、それが正しいとしても、これはリストの残りの部分が正しいという意味ではなく、それぞれの値をテストする必要があります。

A[i + 1] をテストするとき、リストの最後ではなく、リストのn - 1項目に移動します。

于 2012-10-04T19:11:44.670 に答える