web-dev-qa-db-ja.com

理解をリストし、アイテムが一意であるかどうかを確認します

現在アイテムがリストに含まれていない場合にのみアイテムを追加するリスト理解ステートメントを書こうとしています。現在作成中のリストの現在のアイテムを確認する方法はありますか?以下に簡単な例を示します。

入力

{
    "Stefan" : ["running", "engineering", "dancing"],
    "Bob" : ["dancing", "art", "theatre"],
    "Julia" : ["running", "music", "art"]
}

出力

["running", "engineering", "dancing", "art", "theatre", "music"]

リスト内包表記を使用しないコード

output = []
for name, hobbies in input.items():
    for hobby in hobbies:
        if hobby not in output:
            output.append(hobby)

私の試み

[hobby for name, hobbies in input.items() for hobby in hobbies if hobby not in ???]
30
Stefan Bossbaly

setを使用して、理解度を設定できます。

_{hobby for name, hobbies in input.items() for hobby in hobbies}
_

m.wasowskiが言及した のように、ここではnameを使用しないため、代わりにitem.values()を使用できます。

_{hobby for hobbies in input.values() for hobby in hobbies}
_

結果として本当にリストが必要な場合は、これを行うことができます(ただし、通常は問題なくセットを操作できることに注意してください)。

_list({hobby for hobbies in input.values() for hobby in hobbies})
_
34
geckon

この答え が示唆するように、一意性フィルターを使用できます。

def f7(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if not (x in seen or seen_add(x))]

と電話します:

>>> f7(hobby for name, hobbies in input.items() for hobby in hobbies)
['running', 'engineering', 'dancing', 'art', 'theatre', 'music']

一意性フィルターを個別に実装します。これは、デザインルールに「異なるクラス/メソッド/コンポーネント/何でも処理する必要がある」。さらに、必要に応じてこのメソッドを単純に再利用できます。

別の利点は、 リンクされた回答 で記述されているように、アイテムのorderが保持されることです。一部のアプリケーションでは、これが必要になる場合があります。

16

セットと辞書はあなたの友達です:

from collections import OrderedDict
from itertools import chain # 'flattens' collection of iterables

data = {
    "Stefan" : ["running", "engineering", "dancing"],
    "Bob" : ["dancing", "art", "theatre"],
    "Julia" : ["running", "music", "art"]
}

# using set is the easiest way, but sets are unordered:
print {hobby for hobby in chain.from_iterable(data.values())}
# output:
# set(['art', 'theatre', 'dancing', 'engineering', 'running', 'music'])


# or use OrderedDict if you care about ordering:
print OrderedDict(
        (hobby, None) for hobby in chain.from_iterable(data.values())
    ).keys()
# output:
# ['dancing', 'art', 'theatre', 'running', 'engineering', 'music']
7
m.wasowski

本当に本当にリストコンプとリストコンプだけが必要な場合は、

>>> s = []
>>> [s.append(j)  for i in d.values() for j in i if j not in s]
[None, None, None, None, None, None]
>>> s
['dancing', 'art', 'theatre', 'running', 'engineering', 'music']

ここで、sは副作用の結果であり、dは元の辞書です。ここでのユニークな利点は、他のほとんどの回答とは異なり、順序を維持できることです

:これは悪い方法であり、list-compを利用するため、結果は副作用です。練習としてそれをしないでください。この答えは、リストコンプだけを使用してそれを達成できることを示すためです

7
Bhargav Rao

これを書くもう1つの方法は、実際に行っていることをもう少し説明し、ネストされた(double for)内包表記を必要としない方法です。

output = set.union(*[set(hobbies) for hobbies in input_.values()])

これは、入力をより概念的に健全なものに表現する場合、つまり各人の趣味にセットを使用する場合にさらに便利になります(繰り返しが存在してはならないため)。

input_ = {
    "Stefan" : {"running", "engineering", "dancing"},
    "Bob" : {"dancing", "art", "theatre"}, 
    "Julia" : {"running", "music", "art"}
}

output = set.union(*input_.values())
6
Thijs van Dien

リスト内包表記は、この問題にはあまり適していません。集合理解の方が良いと思いますが、それはすでに別の回答で示されているので、コンパクトなワンライナーでこの問題を解決する方法を示します。

list(set(sum(hobbies_dict.values(), [])))

セットの和集合演算子として機能するビットごとのor演算子を使用する別の興味深いソリューション:

from operator import or_
from functools import reduce # Allowed, but unnecessary in Python 2.x
list(reduce(or_, map(set, hobbies_dict.values())))

または(意図しないしゃれ、私は誓います)、ビットごとまたは演算子を使用する代わりに、set.unionを使用して、値のアンパックされたセットマッピングを渡します。 or_およびreduceをインポートする必要はありません。このアイデアは Thijs van Dienの答え に触発されました。

list(set.union(*map(set, hobbies_dict.values())))
5
Shashank

セットを使用:

dict = {
    "Stefan" : ["running", "engineering", "dancing"],
    "Bob" : ["dancing", "art", "theatre"],
    "Julia" : ["running", "music", "art"]
}

myset = set()
for _, value in dict.items():
    for item in value:
        myset.add(item)

print(myset)
4
nullptr

これはどう:

_set(dict['Bob']+dict['Stefan']+dict['Julia'])
>>> set(['art', 'theatre', 'dancing', 'engineering', 'running', 'music'])
_

またはもっとうまく:

_dict = {
    "Stefan" : ["running", "engineering", "dancing"],
    "Bob" : ["dancing", "art", "theatre"],
    "Julia" : ["running", "music", "art"]
}

list_ = []
for y in dict.keys():
    list_ = list_ + dict[y]
list_ = set(list_)
>>> list_
set(['art', 'theatre', 'dancing', 'engineering', 'running', 'music'])
_

list関数をlist(list_)のようにlist_に適用して、セットではなくリストを返すことができます。

4
Plug4