2010-04-28 3 views
4

У меня есть следующий вход:эффективное отображение списка в Python

input = [(dog, dog, cat, mouse), (cat, ruby, python, mouse)] 

и пытается иметь следующий вывод:

outputlist = [[0, 0, 1, 2], [1, 3, 4, 2]] 

outputmapping = {0:dog, 1:cat, 2:mouse, 3:ruby, 4:python, 5:mouse} 

Любые советы о том, как обращаться с учетом масштабируемости в виду (Var вход может стать действительно большим).

+1

@ Феликс - нет, не совсем. Отображение OPs - это логическая организация, которая преобразует выходной список обратно во вход. – PaulMcG

+1

Какие объекты «собака», «кошка» и т. Д.? Они хешируются? –

+5

Откуда «5: мышь»? – SilentGhost

ответ

6

Вы, вероятно, хотите что-то вроде:

import collections 
import itertools 

def build_catalog(L): 
    counter = itertools.count().next 
    names = collections.defaultdict(counter) 
    result = [] 
    for t in L: 
     new_t = [ names[item] for item in t ] 
     result.append(new_t) 
    catalog = dict((name, idx) for idx, name in names.iteritems()) 
    return result, catalog 

С его помощью:

>>> input = [('dog', 'dog', 'cat', 'mouse'), ('cat', 'ruby', 'python', 'mouse')] 
>>> outputlist, outputmapping = build_catalog(input) 
>>> outputlist 
[[0, 0, 1, 2], [1, 3, 4, 2]] 
>>> outputmapping 
{0: 'dog', 1: 'cat', 2: 'mouse', 3: 'ruby', 4: 'python'} 
0

Это одно из возможных решений, хотя оно не является самым большим. Это может быть сделано несколько более эффективно, если вы знаете, сколько элементов каждая запись в списке будет иметь перед собой, предварительно назначив их.

labels=[]; 
label2index={}; 
outputlist=[]; 
for group in input: 
    current=[]; 
    for label in group: 
     if label not in label2index: 
      label2index[label]=len(labels); 
      labels.append(label); 
     current.append(label2index[label]); 
    outputlist.append(current); 

outputmapping={}; 
for idx, val in enumerate(labels): 
    outputmapping[idx]=val; 
2

Этот класс автоматически сопоставляет объекты увеличивающихся целочисленных значений: Использование

class AutoMapping(object): 
    def __init__(self): 
     self.map = {} 
     self.objects = [] 

    def __getitem__(self, val): 
     if val not in self.map: 
      self.map[val] = len(self.objects) 
      self.objects.append(val) 
     return self.map[val] 

Пример , для вашего ввода :

>>> input = [('dog', 'dog', 'cat', 'mouse'), ('cat', 'ruby', 'python', 'mouse')] 
>>> map = AutoMapping() 
>>> [[map[x] for x in y] for y in input] 
[[0, 0, 1, 2], [1, 3, 4, 2]] 
>>> map.objects 
['dog', 'cat', 'mouse', 'ruby', 'python'] 
>>> dict(enumerate(map.objects)) 
{0: 'dog', 1: 'cat', 2: 'mouse', 3: 'ruby', 4: 'python'} 
0

У меня была такая же проблема довольно часто в своих проектах, так что я завернутые класс некоторое время назад, что делает именно это: пример

class UniqueIdGenerator(object): 
    """A dictionary-like class that can be used to assign unique integer IDs to 
    names. 

    Usage: 

    >>> gen = UniqueIdGenerator() 
    >>> gen["A"] 
    0 
    >>> gen["B"] 
    1 
    >>> gen["C"] 
    2 
    >>> gen["A"]  # Retrieving already existing ID 
    0 
    >>> len(gen)  # Number of already used IDs 
    3 
    """ 

    def __init__(self, id_generator=None): 
     """Creates a new unique ID generator. `id_generator` specifies how do we 
     assign new IDs to elements that do not have an ID yet. If it is `None`, 
     elements will be assigned integer identifiers starting from 0. If it is 
     an integer, elements will be assigned identifiers starting from the given 
     integer. If it is an iterator or generator, its `next` method will be 
     called every time a new ID is needed.""" 
     if id_generator is None: 
      id_generator = 0 
     if isinstance(id_generator, int): 
      import itertools 
      self._generator = itertools.count(id_generator) 
     else: 
      self._generator = id_generator 
     self._ids = {} 

    def __getitem__(self, item): 
     """Retrieves the ID corresponding to `item`. Generates a new ID for `item` 
     if it is the first time we request an ID for it.""" 
     try: 
      return self._ids[item] 
     except KeyError: 
      self._ids[item] = self._generator.next() 
      return self._ids[item] 

    def __len__(self): 
     """Retrieves the number of added elements in this UniqueIDGenerator""" 
     return len(self._ids) 

    def reverse_dict(self): 
     """Returns the reversed mapping, i.e., the one that maps generated IDs to their 
     corresponding items""" 
     return dict((v, k) for k, v in self._ids.iteritems()) 

    def values(self): 
     """Returns the list of items added so far. Items are ordered according to 
     the standard sorting order of their keys, so the values will be exactly 
     in the same order they were added if the ID generator generates IDs in 
     ascending order. This hold, for instance, to numeric ID generators that 
     assign integers starting from a given number.""" 
     return sorted(self._ids.keys(), key = self._ids.__getitem__) 

Использование:

>>> input = [(dog, dog, cat, mouse), (cat, ruby, python, mouse)] 
>>> gen = UniqueIdGenerator() 
>>> outputlist = [[gen[x] for x in y] for y in input] 
[[0, 0, 1, 2], [1, 3, 4, 2]] 
>>> print outputlist 
>>> outputmapping = gen.reverse_dict() 
>>> print outputmapping 
{0: 'dog', 1: 'cat', 2: 'mouse', 3: 'ruby', 4: 'python'}