2009-09-09 106 views
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'] 
} 

我不知道是否有一個優雅和Python的解決了這個問題。

我也開到更好的術語比create_lookup_list

回答

3

defaultdict結合itertools.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 

編輯:注意count().next成爲在Python 3

+0

我只是想把它放在一起,但沒有得到defaultdict的defaultdict ...做得很好! – PaulMcG 2009-09-10 01:32:10

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 
+0

count().__next__lambda: next(count())我猜速度可能沒有關係,但我不知道爲什麼許多其他的答案是他們可以像你一樣使用字典時使用線性搜索。我唯一的抱怨是反轉字符串 - >索引映射,你使用排序。 – 2009-09-09 20:47:06

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 
+0

爲什麼使用線性時間list.index? – 2009-09-09 20:47:52

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 
+1

問題是,如果值不在表[鍵]中的值不是O [n]的複雜度,如果一個組中有許多元素可能會成爲一個問題。我選擇了字典索引分配,因爲'如果鍵入字典'更快 – 2009-09-09 20:28:26

+0

因此,您可以使用** S.Lott **的查找表結構 - 如果鍵入字典**檢查並且沒有**,將會出現**將需要index()**調用。 – 2009-09-09 20:40:41

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'}} 
+1

但我想查找表給我一個給定的ID的原始元素 – 2009-09-09 20:36:07

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 
2

在奧托的答案(或其他任何人與字符串> ID類型的字典的),我會更換(如果沉迷在速度是你的事):

# 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()) 

這樣更好一些,因爲直接分配到反向數組中的每個項目會比排序更快。