4

これが何を意味するのかを説明するために、ここに例を示します

messages = [
  ('Ricky',  'Steve',  'SMS'),
  ('Steve',  'Karl',   'SMS'),
  ('Karl',   'Nora',   'Email')
]

このリストとグループの定義を整数のリストとルックアップディクショナリに変換して、グループ内の各要素が一意のIDを取得できるようにします。そのIDは、次のようにルックアップテーブルの要素にマップする必要があります

messages_int, lookup_table = create_lookup_list(
              messages, ('person', 'person', 'medium'))

print messages_int
[ (0, 1, 0),
  (1, 2, 0),
  (2, 3, 1) ]

print lookup_table
{ 'person': ['Ricky', 'Steve', 'Karl', 'Nora'],
  'medium': ['SMS', 'Email']
}

この問題に対するエレガントでパイソン的な解決策があるのだろうか。

私はまた、他よりも優れた用語を受け入れていcreate_lookup_listます

4

7 に答える 7

3

defaultdictitertools.count().nextこの方法と組み合わせると、一意のアイテムに識別子を割り当てることができます。これをあなたのケースに適用する方法の例を次に示します。

from itertools import count
from collections import defaultdict

def create_lookup_list(data, domains):
    domain_keys = defaultdict(lambda:defaultdict(count().next))
    out = []
    for row in data:
        out.append(tuple(domain_keys[dom][val] for val, dom in zip(row, domains)))
    lookup_table = dict((k, sorted(d, key=d.get)) for k, d in domain_keys.items())
    return out, lookup_table

編集:Python3にcount().nextなるcount().__next__lambda: next(count())Python3になることに注意してください。

于 2009-09-09T22:04:41.107 に答える
2

鉱山はほぼ同じ長さと複雑さです:

import collections

def create_lookup_list(messages, labels):

    # Collect all the values
    lookup = collections.defaultdict(set)
    for msg in messages:
        for l, v in zip(labels, msg):
            lookup[l].add(v)

    # Make the value sets lists
    for k, v in lookup.items():
        lookup[k] = list(v)

    # Make the lookup_list
    lookup_list = []
    for msg in messages:
        lookup_list.append([lookup[l].index(v) for l, v in zip(labels, msg)])

    return lookup_list, lookup
于 2009-09-09T20:17:44.517 に答える
2

Ottoの答え(またはstring-> id dictsを持つ他の人)では、私は置き換えます(速度にこだわることがあなたのものである場合):

# create the lookup table
lookup_dict = {}
for group in indices:
    lookup_dict[group] = sorted(indices[group].keys(),
            lambda e1, e2: indices[group][e1]-indices[group][e2])

# k2i must map keys to consecutive ints [0,len(k2i)-1)
def inverse_indices(k2i):
    inv=[0]*len(k2i)
    for k,i in k2i.iteritems():
        inv[i]=k
    return inv

lookup_table = dict((g,inverse_indices(gi)) for g,gi in indices.iteritems()) 

逆配列の各項目に直接割り当てる方が、並べ替えよりも高速であるため、これは優れています。

于 2009-09-09T21:01:32.223 に答える
1

これは少し単純で、より直接的です。

from collections import defaultdict

def create_lookup_list( messages, schema ):
    def mapped_rows( messages ):
        for row in messages:
            newRow= []
            for col, value in zip(schema,row):
                if value not in lookups[col]:
                    lookups[col].append(value)
                code= lookups[col].index(value)
                newRow.append(code)
            yield newRow
    lookups = defaultdict(list)
    return list( mapped_rows(messages) ), dict(lookups)  

ルックアップがリストではなく適切な辞書である場合、これはさらに単純化できます。
「ルックアップテーブル」を次の構造にします

{ 'person': {'Ricky':0, 'Steve':1, 'Karl':2, 'Nora':3},
  'medium': {'SMS':0, 'Email':1}
}

また、複雑さをさらに軽減することができます。

次のように、ルックアップのこの作業コピーをその逆に変換できます。

>>> lookups = { 'person': {'Ricky':0, 'Steve':1, 'Karl':2, 'Nora':3},
      'medium': {'SMS':0, 'Email':1}
    }
>>> dict( ( d, dict( (v,k) for k,v in lookups[d].items() ) ) for d in lookups )
{'person': {0: 'Ricky', 1: 'Steve', 2: 'Karl', 3: 'Nora'}, 'medium': {0: 'SMS', 1: 'Email'}}
于 2009-09-09T20:26:21.993 に答える
1

これが私自身の解決策です-私はそれが最高だとは思えません

def create_lookup_list(input_list, groups):
    # use a dictionary for the indices so that the index lookup 
    # is fast (not necessarily a requirement)
    indices = dict((group, {}) for group in groups) 
    output = []

    # assign indices by iterating through the list
    for row in input_list:
        newrow = []
        for group, element in zip(groups, row):
            if element in indices[group]:
                index = indices[group][element]
            else:
                index = indices[group][element] = len(indices[group])
            newrow.append(index)
        output.append(newrow)

    # create the lookup table
    lookup_dict = {}
    for group in indices:
        lookup_dict[group] = sorted(indices[group].keys(),
                lambda e1, e2: indices[group][e1]-indices[group][e2])

    return output, lookup_dict
于 2009-09-09T19:53:48.830 に答える
0

これが私の解決策です、それは良くありません-それはただ違うだけです:)

def create_lookup_list(data, keys):
  encoded = []
  table = dict([(key, []) for key in keys])

  for record in data:
      msg_int = []
      for key, value in zip(keys, record):
          if value not in table[key]:
              table[key].append(value)
          msg_int.append(table[key].index(value))  
      encoded.append(tuple(msg_int))

  return encoded, table
于 2009-09-09T20:20:25.530 に答える
0

これが私のものです。内部関数を使用すると、インデックスタプルをジェネレーターとして記述できます。

def create_lookup_list( data, format):
    table = {}
    indices = []
    def get_index( item, form ):
        row = table.setdefault( form, [] )
        try:
            return row.index( item )
        except ValueError:
            n = len( row )
            row.append( item )
            return n
    for row in data:
        indices.append( tuple( get_index( item, form ) for item, form in zip( row, format ) ))

    return table, indices
于 2009-09-09T20:55:53.953 に答える