2011-10-20 11 views
7

listdictです。最初の変数を空白で分割する場合はlistnamedtuple(推奨)または単純なtupleに変換する必要があります。辞書のリストを名前付きタプルのリストに変換するPythonicの方法

それを行うにはもっとpythonicな方法はありますか?

私はコードを少し簡略化しました。理解、ジェネリック表現、itertoolsの使用法が歓迎されました。

データイン:

dl = [{'a': '1 2 3', 
     'd': '*', 
     'n': 'first'}, 
     {'a': '4 5', 
     'd': '*', 'n': 
     'second'}, 
     {'a': '6', 
     'd': '*', 
     'n': 'third'}, 
     {'a': '7 8 9 10', 
     'd': '*', 
     'n': 'forth'}] 

単純なアルゴリズム:

from collections import namedtuple 

some = namedtuple('some', ['a', 'd', 'n']) 

items = [] 
for m in dl: 
    a, d, n = m.values() 
    a = a.split() 
    items.append(some(a, d, n)) 

出力:以下

[some(a=['1', '2', '3'], d='*', n='first'), 
some(a=['4', '5'], d='*', n='second'), 
some(a=['6'], d='*', n='third'), 
some(a=['7', '8', '9', '10'], d='*', n='forth')] 

答えて

7

、@Petr Viktorinは私のオリジナルの答えとあなたの初期の問題を指摘ソリューション:

警告!辞書のvalues()は、特定の順序ではありません!この解決策が機能し、a、d、nが実際にこの順番で返された場合、それはちょうど偶然のことです。別のバージョンのPythonを使用するか、別の方法でdictsを作成すると、破損する可能性があります。

は(私が最初の場所でこれをピックアップしていなかった種類の恥ずかしいだし、それのために45の担当者を持って!)の代わりに

使用する@ eryksunの提案:

items = [some(m['a'].split(), m['d'], m['n']) for m in dl] 

私のオリジナルで間違った答えです。 OrderedDictのリストがない限り使用しないでください。

items = [some(a.split(), d, n) for a,d,n in (m.values() for m in dl)] 
+0

ありがとうを、それは何です必要があります – scraplesh

+2

警告!辞書の 'values()'は[特定の順序ではありません](http://docs.python.org/library/stdtypes.html#dict.items)です!この解決法がうまくいけば、 'a、d、n'が実際にこの順番で返されます。ただの偶然です。別のバージョンのPythonを使用するか、別の方法でdictsを作成すると、破損する可能性があります。 @ eryksunのコメントのように、キーを直接使用してください。 –

+0

@klesh - 編集を参照してください、またはこれはあなたをかむために戻ってきます! – detly

2

別のオプションではなく、それは他のものより良いか悪いのかどうかを確認します。

class some(namedtuple('some', 'a d n')): 
    def __new__(cls, **args): 
     args['a'] = args['a'].split() 
     return super(some, cls).__new__(cls, **args) 

items = list(some(**m) for m in dl) 

ところで、私は、サブクラスsomeとして基底クラスに同じ名前を与えることに絶対にコミットしていませんよ。結果クラスが名前someを使用して文字列に変換され、特に問題が発生することはありませんが、クラス名でデバッグしていると混乱する可能性があるため、好きです。それで大事にしてください。

異なるトリックを使用して

か、同じアイデア:あなたは手の前にdictsの分野について知らない場合に加えて

some = namedtuple('some', 'a d n') 

def make_some(args): 
    args = args.copy() 
    args['a'] = args['a'].split() 
    return some(**args) 

items = map(make_some, dl) # NB: this doesn't return a list in Python 3 
2

@detlyが提供する答えは、あなたがnamedtupleクラスを構築することができます

some = namedtuple('some', set(k for k in d.keys() for d in dl)) 
2

私はちょうど私が名前付きタプルと辞書をそんなに愛しているからこそチャイムします:ここで

は、辞書のあなたの最初の処理を行うことができ、その中にdictの理解、とリスト内包です:

split_dictionaries = \ 
    [{key: value.split() for k, value in d.iteritems()} for d in dl] 

私は頻繁に再帰的にnamedtuplesに辞書を変換し、私は「タッパーウェア」と呼ぶのレシピを使用します。コードについてはthe gist hereを参照してください。ここでは、単純化してここに統合し、この操作を行うきれいな方法を示します。

import collections 

def namedtuple_from_mapping(mapping, name="Tupperware"): 
    this_namedtuple_maker = collections.namedtuple(name, mapping.iterkeys()) 
    return this_namedtuple_maker(**mapping) 

だから機能を考えると、あなたがこれを行うことができます - 私たちはすぐにリファクタリングされます:より良いカプセル化と読みやすさと

split_namedtuples = [ 
    namedtuple_from_mapping(
     {key: value.split() for k, value in d.iteritems()} 
    ) for d in dl 
] 

そして今:

def format_string(string): 
    return string.split() 

def format_dict(d): 
    return {key: format_string(value) for key, value in d.iteritems()} 

formatted_namedtuples = [namedtuple_from_mapping(format_dict(d)) for d in dl] 
関連する問題