-1

次のようなリストのリストがあります。

aList = [[10564, 15, 1], [10564, 13, 1], [10589, 18, 1], [10637, 39, 1], [10662, 38, 1], [10837, 45, 1], [3, 17, 13], [7, 21, 13], [46, 1, 13]]

3番目の要素が1の場合、2番目の要素が最も低いリストを見つけたかったので、その上に[10564, 13, 1]. 私はいくつかの助けを借りてそれを行いました(key=lambda k:k[1]を完全には理解していませんが、それはどういう意味ですか?):

i = min((x for x in aList if (str(x[2])=="1")), key=lambda k:k[1])

私が自分でそれを行うことを理解した方法は次のとおりです。

target = min(x[1] for x in aList if (str(x[2])=="1"))
matches = [x for x in aList if (x[1] == target) and (str(x[2])=="1")]

ただし、これを変更したいのですが、代わりにすべての隣接リストを比較し、それらの 2 番目の要素を一緒に追加し、最小のリストのペアを見つけて、最後にそのペアから最小の 2 番目の要素を持つ 1 つのリストを返します。すべては 3 番目の要素が 1 の場合です。これはどのように行うのですか?

編集: サンプル入力:

aList = [[10564, 15, 1], [10564, 13, 1], [10589, 18, 1], [10637, 39, 1], [10662, 38, 1], [10837, 45, 1], [3, 17, 13], [7, 21, 13], [46, 1, 13]]

サンプル出力ステージ 1:

[10564, 15, 1], [10564, 13, 1]

15+13 = 28 であり、2 番目の要素の追加がこれほど低いペアは他にないため、これは最も低い隣接ペアです。

最終的な出力は、このペアの最低です。

[10564, 13, 1]
4

2 に答える 2

3

key引数は、によってmin最小値を決定するものを示します。

key引数を指定しないminと、任意のタプル全体が他のタプルと比較され、タプル内の最初の要素が最初に比較されます。関数は入力シーケンスのkey各要素に対して呼び出され、最小要素はそのキーの戻り値のみによって決定されます。lambda k: k[1]タプルの 2 番目の要素を返します。

次の 2 つの結果を比較します。

>>> example = [(5, 1), (4, 2), (3, 3), (2, 4), (1, 5)]
>>> min(example)
(1, 5)
>>> min(example, key=lambda element: element[1])
(5, 1)

最初の例では、key関数は提供されず、min()各タプルをそのまま比較します。2 番目の例では、関数が返すmin()ものだけを見て、異なる要素を最小値として選択します。key()

あなたはその主要な機能で本当に船外に出ることができます:

>>> min(example, key=lambda element: (element[0] / element[1]) + element[1])
(4, 2)

usingstrは実際には必要なく、式全体が過度に冗長です。次のように単純化できます。

i = min((x for x in aList if x[2] == 1), key=lambda k: k[1])

または使用operator.itemgetter

from operater import itemgetter

i = min((x for x in aList if x[2] == 1), key=itemgetter(1))

itertools隣接するペアを比較するには、ヘルパー関数が必要です:

from itertools import tee, izip

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

次に、次を使用して、「最後の要素が 1 である」基準をフィルターに移動する方が簡単ですitertools.ifilter

from itertools import ifilter

last_is_one = ifilter(lambda x: x[2] == 1, aList)
paired = pairwise(last_is_one)

これで、実際の作業を行うことができます。隣接するリストの各ペアについて、2 番目の要素の合計が最小のペアを見つけ、そのペアから 2 番目の要素ごとに最小のものを見つけます。

# find minimum pair by second elements summed
minpair = min(paired, key=lambda pair: pair[0][1] + pair[1][1])
minimum = min(minpair, key=itemgetter(1))

すべてをまとめると、フィルタリングの責任は関数の呼び出し元に委ねられます。

from operater import itemgetter
from itertools import tee, izip

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

def neighbouring_minimum(iterable):
    paired = pairwise(iterable)

    # find minimum pair by second elements summed
    minpair = min(paired, key=lambda pair: pair[0][1] + pair[1][1])
    return min(minpair, key=itemgetter(1))

サンプル入力の場合:

>>> from itertools import ifilter
>>> aList = [[10564, 15, 1], [10564, 13, 1], [10589, 18, 1], [10637, 39, 1], [10662, 38, 1], [10837, 45, 1], [3, 17, 13], [7, 21, 13], [46, 1, 13]]
>>> filtered = ifilter(lambda x: x[2] == 1, aList)
>>> neighbouring_minimum(filtered)
[10564, 13, 1]

最小値の基準を別のキー引数に移動することもできます:

def neighbouring_minimum(iterable, key=None):
    if key is None:
        # default to the element itself
        key = lambda x: x

    paired = pairwise(iterable)

    # find minimum pair by key summed
    minpair = min(paired, key=lambda pair: sum(map(key, pair)))
    return min(minpair, key=key)

neighbouring_minimum(ifilter(lambda x: x[2] == 1, aList), key=itemgetter(1))
于 2013-04-19T10:20:04.440 に答える
3

一般的な理解のために、ここにはいくつかの優れた回答がありますが、このようlambdaに再現することはできませんでした。

あなたの特定のケースでは:(私はそれを少しきれいにしました)

i = min((x for x in aList if x[2]==1)), key=lambda k:k[1])

次のように読む必要があります。

some_generator = (x for x in aList if x[2]==1)) # a generator of list elements 
                                                # where the 3rd element == 1
i = min(some_generator, key=lambda k:k[1])      # minimum with respect to the
                                                # 2nd element

lambda上記のコードでは、渡された各 3 要素リストをインターセプトしmin()、2 番目の値を返します。これはmin()、最初の要素で最小化するのではなく、デフォルトで最小化するように指示しますが、2 番目の要素で最小化します。以下の単純なケースでこれが明確になることを願っています。

>>> min([3,0],[1,2],[2,1])
[1,2]
>>> min([3,0],[1,2],[2,1], key=lambda x:x[1])
[3,0]

2番目の質問ですが、これで目的が達成されると思います...

[編集: ラップ アラウンド機能を削除しました。以下のコメントを参照してください。これはまた、モジュラスが冗長であることを意味するため、コードはよりクリーンになります!]

# Accept only elements where 3rd value is a 1 
only_ones = [x for x in aList if x[2]==1]

# neighbours will hold pairs of entries for easy lambda minimization
neighbours = []
for i, element in enumerate(only_ones[:-1]) :
   neighbours.append([element, only_ones[i+1]])

# Get minimum pair with respect to the sum of the pairs' middle elements first
# then get minimum of the resulting pair with respect to to middle element
i = min(min(neighbours, key=lambda k: k[0][1] + k[1][1]),
        key=lambda k:k[1])

後から考えると、neighboursおそらくジェネレーターとしての方が優れている

neighbours = ([x, only_ones[i+1]] for i, x in enumerate(only_ones[:-1])) 

そして最後に、過剰で読めないリスト/ジェネレーター理解のファンのために

i = min(min(([x, only_ones[i+1]] 
              for i, x in enumerate([x for x in aList if x[2]==1][:-1])) ,
                 key=lambda k: k[0][1] + k[1][1]),
                    key=lambda k: k[1])

(我慢できなくてごめんなさい!)

于 2013-04-19T10:47:12.483 に答える