5

以下は、順序を維持しながらリスト内の重複を削除する簡単な関数です。私はそれを試しましたが、実際に機能するので、ここでの問題は私の理解です。特定のアイテムを2回実行すると、そのアイテムは既に一意のセットから削除されているためuniq.remove(item)、エラーが返されるように見えます(KeyErrorまたは私は思いますか?)。ValueErrorそうではありませんか?

def unique(seq):
    uniq = set(seq)  
    return [item for item in seq if item in uniq and not uniq.remove(item)]
4

6 に答える 6

9

if item in uniqアイテムが削除される前に実行されるチェックがあります。andオペレーターは「短絡」するという点で優れています。これは、左側の条件がFalse-likeと評価された場合、右側の条件は評価されないことを意味します-式が-likeになることはできないことはすでにわかっていますTrue

于 2012-11-02T14:14:33.507 に答える
4

set.removeインプレース操作です。これは、何も返さないことを意味します(まあ、それは返しますNone); とbool(None)ですFalse

したがって、リスト内包表記は事実上次のとおりです。

answer = []
for item in seq:
    if item in uniq and not uniq.remove(item):
        answer.append(item)

Pythonは(他の人が指摘しているように)条件の短絡を行うので、これは事実上次のようになります。

answer = []
for item in seq:
    if item in uniq:
        if not uniq.remove(item):
            answer.append(item)

もちろん、unique.remove(item)returns None(のboolFalse)なので、両方の条件が評価されるか、どちらも評価されません。

2番目の条件が存在する理由は、から削除するためitemですuniq。このように、item(の重複として)再度遭遇した場合、前回そこで検出されたときから削除されたため、でseq検出されません。uniquniq

ここで、変数を変更する条件は悪いスタイルと見なされるため、これはかなり危険であることに注意してください(その機能に完全に精通していないときに、このような条件をデバッグすることを想像してください)。条件文は、チェックする変数を実際に変更するべきではありません。そのため、変数を読み取るだけで、変数に書き込むことはできません。

お役に立てれば

于 2012-11-02T14:29:05.370 に答える
1

mgilsonと他の人たちは、いつものように、この質問にうまく答えました。私は、Pythonでこれを行うための標準的な方法、つまり、以下に引用されているドキュメントのレシピセクションunique_everseenレシピを使用する方法を指摘するかもしれないと思いました。itertools

from itertools import ifilterfalse

def unique_everseen(iterable, key=None):
    "List unique elements, preserving order. Remember all elements ever seen."
    # unique_everseen('AAAABBBCCDAABBB') --> A B C D
    # unique_everseen('ABBCcAD', str.lower) --> A B C D
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in ifilterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element
于 2012-11-02T14:43:33.090 に答える
0
def unique_with_order(seq):
    final = []
    for item in seq:
        if item not in final:
            final.append(item)
    return final


print unique_with_order([1,2,3,3,4,3,6])

分解して、単純にしてください:)最近、すべてがリスト内包表記である必要はありません。

于 2012-11-02T14:15:45.913 に答える
0

@mgilsonの答えは正しいものですが、ここでは、参考までに、同じ関数のレイジー(ジェネレーター)バージョンの可能性があります。これは、要素のセットが機能する限り、メモリに収まらないイテレータ(無限イテレータを含む)に対して機能することを意味します。

def unique(iterable):
    uniq = set()
    for item in iterable:
        if item not in uniq:
            uniq.add(item)
            yield item
于 2012-11-02T14:35:41.090 に答える
-1

この関数を初めて実行する[1,2,3,4]と、リスト内包表記が取得され、セットuniqが空になります。この関数を2回実行すると[]、セットuniqが空になるため、次のようになります。2回目の実行でエラーが発生しない理由は、Pythonのand短絡です。最初の句(item in uniq)がfalseであると見なされ、2番目の句を実行する必要がありません。

于 2012-11-02T14:21:18.993 に答える