将对象列表转换为整数列表和查找表
为了说明我的意思,这里有一个例子
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
更好的术语来描述这个。
7 个回答
2
在Otto的回答中(或者其他任何使用字符串到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())
这样做更好,因为直接给反向数组中的每个项目赋值,比排序要快。
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
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
补充说明:请注意,在 Python 3 中,count().next
变成了 count().__next__
或者 lambda: next(count())
。