マッピングのリストから一意のアイテムを抽出する
-
06-07-2019 - |
質問
彼は、最もPython的な解決策を探す興味深い問題です。マッピングのリスト {'id':id、 'url':url}
があるとします。リスト内の一部の id
が重複しています。重複するものをすべて削除して、新しいリストを作成します。私は次の機能を思いつきました:
def unique_mapping(map):
d = {}
for res in map:
d[res['id']] = res['url']
return [{'id': id, 'url': d[id]} for id in d]
かなり効率的だと思います。しかし、「もっとPythonic」なのはありますか?方法?またはおそらくより効率的な方法ですか?
解決
ジェネレーター式を使用して最初の辞書を作成し、別のマッピングを作成する必要性をなくすために、サンプルをわずかに書き直すことができます。古いものを再利用するだけです:
def unique_mapping(mappings):
return dict((m['id'], m) for m in mappings).values()
これはワンライナーとして出てきましたが、それでもかなり読みやすいと思います。
元のソリューションと私のソリューションを使用する際には、次の2つの点に注意する必要があります。
- アイテムは常に元の順序で返されるとは限りません
- 後のエントリは同じidを持つ以前のエントリを上書きします
気にしない場合は、上記の解決策をお勧めします。それ以外の場合、この関数は順序を保存し、最初に遭遇したIDを優先的に処理します。
def unique_mapping(mappings):
addedIds = set()
for m in mappings:
mId = m['id']
if mId not in addedIds:
addedIds.add(mId)
yield m
ジェネレーターではなくリストが必要な場合は、 list(unique_mappings(mappings))
で呼び出す必要があります。
他のヒント
改善できることがいくつかあります。
-
2つのループを実行しています。1つは元の辞書に対して実行し、もう1つは結果の辞書に対して実行します。代わりに1ステップで結果を作成できます。
-
リスト全体を事前に作成しないように、ジェネレータを使用するように変更できます。 (必要な場合はlist(unique_mapping(items))を使用して完全なリストに変換します)
-
重複をチェックするだけで値を保存する必要はありません。代わりにセットを使用できます。
-
元の要素を返すのではなく、各要素の辞書を再作成しています。これは実際には必要な場合があります(たとえば、それらを変更し、オリジナルに触れたくない場合)が、そうでない場合は、すでに作成された辞書を使用する方が効率的です。
実装は次のとおりです。
def unique_mapping(items):
s = set()
for res in items:
if res['id'] not in s:
yield res
s.add(res['id'])
これはもっと簡単にできると思います。辞書は重複キーを許容しません。マッピングのリストをマッピングの辞書にします。これにより重複が削除されます。
>>> someListOfDicts= [
{'url': 'http://a', 'id': 'a'},
{'url': 'http://b', 'id': 'b'},
{'url': 'http://c', 'id': 'a'}]
>>> dict( [(x['id'],x) for x in someListOfDicts ] ).values()
[{'url': 'http://c', 'id': 'a'}, {'url': 'http://b', 'id': 'b'}]