1

混合型の辞書 (int、float、string、numpy.arrays を含む) で比較できるようにしたいと考えています。私の最小限の例には辞書のリストがあり、関数 (またはジェネレーター) でそのリストを反復処理し、その関数 (またはジェネレーター) への **kwargs 入力で指定されたキーと値のペアを含む要素 (辞書) を選択したいと考えています。 )。

import re
list_of_dicts = [{'s1':'abcd', 's2':'ABC', 'i':42, 'f':4.2},
                 {'s2':'xyz', 'i':84, 'f':8.4}]

def find_list_element(**kwargs):
    for s in list_of_dicts:
        for criterion, criterion_val in kwargs.iteritems():
            if type(criterion_val) is str:
                if re.match(criterion_val, s.get(criterion, 'unlikely_return_val')):
                    yield s
                    continue
            if s.get(criterion, None) == criterion_val:
                yield s

print [a for a in find_list_element(i=41)]       # []
print [a for a in find_list_element(i=42)]       # [{'i': 42, 's2': 'ABC', 's1': 'abcd', 'f': 4.2}]
print [a for a in find_list_element(s1='xyz')]   # []
print [a for a in find_list_element(s2='xyz')]   # [{'i': 84, 's2': 'xyz', 'f': 8.4}]
print [a for a in find_list_element(s2='[a-z]')] # [{'i': 84, 's2': 'xyz', 'f': 8.4}]

上記の2つの問題は次のとおりです。

  1. 関数が文字列である比較を要求する場合、単純な文字列比較の代わりに正規表現一致 (re.search または re.match) に切り替えたいと思います。上記のコードでは、これは悪意のある型チェックによって実現されており、それほどエレガントには見えません。型チェックを含まないより良い解決策はありますか? それとも、これは Python で型チェックが許可されている場合ですか?

  2. **kwargsもちろん、複数の比較を含めることができます。現在、いくつかのフラグを含むソリューションしか考えられません (found = Falseに切り替えられ、found = Trueの各反復の最後に評価されますlist_of_dicts)。それを生成するかどうかを決定する前に、各 s の比較結果を蓄積する賢い方法はありますか?

この辞書のコレクション全体をよりきれいにする方法はありますか?

PS: これの実際の使用例には、取得した MRI データセット (BRUKER) の表現が含まれます。データセットは、スキャンを表すオブジェクトの一部である dict に変換したパラメーター ファイルによって特徴付けられます。これらのデータセットを収集していますが、これらのパラメーター ファイルによって指定された特定の基準に基づいてさらにフィルター処理したいと考えています。これらのパラメーターは、文字列、数値、およびその他のあまり便利でない型にすることができます。

更新と蒸留された回答

@BrenBarnと@srgergによる入力から得られたコンセンサス回答を考え出すとしたら、これになります

list_of_dicts = [{'s1':'abcd', 's2':'ABC', 'i':42, 'f':4.2},
                 {'s2':'xyz', 'i':84, 'f':8.4}]

 # just making up some comparison strategies
def regex_comp(a,b): return re.match(a,b)
def int_comp(a,b): return a==b
def float_comp(a,b): return round(a,-1) == round (b,-1)

pre_specified_comp_dict = {frozenset(['s1','s2']) : regex_comp,
                           frozenset(['i']): int_comp,
                           frozenset(['f']): float_comp}

def fle_new(**kwargs):
    chosen_comps={}
    for key in kwargs.keys():
        # remember, the keys here are frozensets
        cand_comp = [x for x in pre_specified_comp_dict if key in x]
        chosen_comps[key] = pre_specified_comp_dict[cand_comp[0]]

    matches = lambda d: all(k in d and chosen_comps[k](v, d[k])
                            for k, v in kwargs.items())

    return filter(matches, list_of_dicts)

ここでの唯一の課題は、pre_specified_comp_dict.

4

3 に答える 3

1

これが私があなたのfind_list_element機能を実装する方法です。依然として The Reviled Type Checking (TM) を使用していますが、もう少し雄弁に見えます。

def find_list_element(**kwargs):
    compare = lambda e, a: re.match(e, a) is not None if isinstance(e, str) else e == a
    matches = lambda d: all(k in d and compare(v, d[k]) for k, v in kwargs.items())
    return filter(matches, list_of_dicts)

(ちなみに、私は Python 3 を使用していますが、コードは Python 2.7 で動作しますが、BrenBarn が既に指摘しているようにbasestringではなく、使用する必要があります)。str

比較結果を蓄積する必要がないように、Python のall関数を使用していることに注意してください。

于 2013-04-08T05:58:19.260 に答える
0

複数の比較の必要性を解決する以下のコードを見ることができます。

def find_dict(**kwargs):
    for data in lds: # lds is the same as list_of_dicts
        for key, val in kwargs.iteritems():
                 if not data.get(key, False) == val: return False
         else:
                 yield data

O/P:

find_dict(i=42, s1='abcd')
{'i': 42, 's2': 'ABC', 's1': 'abcd', 'f': 4.2}

正規表現比較用のコードを含めていません!

乾杯!

于 2013-04-08T05:59:24.230 に答える