3

さまざまな要素を含む同じ長さの 2 つのリストがあります。それらを比較して、両方のリストに存在する要素の数を見つけようとしていますが、インデックスが異なります。

私が何を意味するかを示すために、入力/出力の例をいくつか示します。

>>> compare([1, 2, 3, 4], [4, 3, 2, 1])
4
>>> compare([1, 2, 3], [1, 2, 3])
0
# Each item in the first list has the same index in the other
>>> compare([1, 2, 4, 4], [1, 4, 4, 2])
2
# The 3rd '4' in both lists don't count, since they have the same indexes
>>> compare([1, 2, 3, 3], [5, 3, 5, 5])
1
# Duplicates don't count

リストは常に同じサイズです。

これは私がこれまでに持っているアルゴリズムです:

def compare(list1, list2):
    # Eliminate any direct matches
    list1 = [a for (a, b) in zip(list1, list2) if a != b]
    list2 = [b for (a, b) in zip(list1, list2) if a != b]

    out = 0
    for possible in list1:
        if possible in list2:
            index = list2.index(possible)
            del list2[index]
            out += 1
    return out

同じことを行うためのより簡潔で雄弁な方法はありますか?

4

3 に答える 3

1

重複はカウントされないため、sets を使用して、それぞれの要素のみを見つけることができますlist。Asetは一意の要素のみを保持します。次に、両方で共有されている要素のみを選択しますlist.index

def compare(l1, l2):
    s1, s2 = set(l1), set(l2)
    shared = s1 & s2 # intersection, only the elements in both
    return len([e for e in shared if l1.index(e) != l2.index(e)])

必要に応じて、実際にこれをワンライナーにすることができます

def compare(l1, l2):
    return len([e for e in set(l1) & set(l2) if l1.index(e) != l2.index(e)])

別:

機能的には、ビルトインを使用できますreduce(python3 では、from functools import reduce最初に行う必要があります)。これにより、過剰なメモリ使用量を節約するリストの構築が回避されます。ラムダ関数を使用して作業を行います。

def compare(l1, l2):
    return reduce(lambda acc, e: acc + int(l1.index(e) != l2.index(e)),
                  set(l1) & set(l2), 0)

簡単な説明:

reduce伝統的にイテラブルを単一のアイテムに減らす関数型プログラミング構造です。ここでは、交差を単一の値reduceに減らすために使用します。set

lambda関数は無名関数です。言うことは、関数に名前がないことを除けば、 lambda x, y: x + 1言うことと同じです。最初の引数として関数を取ります。が使用されたときに受け取る最初の引数 a は、前の関数 の結果です。def func(x, y): return x + yreducelambdareduceaccumulator

set(l1) & set(l2)l1は、 と の両方にある固有の要素で構成されるセットl2です。これが繰り返され、各要素が一度に 1 つずつ取り出され、lambda関数の 2 番目の引数として使用されます。

0アキュムレータの初期値です。これを使用するのは、開始するインデックスが異なる共有要素が 0 個あると想定しているためです。

于 2013-05-13T18:19:33.010 に答える