Konvertieren Liste von Objekten auf eine Liste von ganzen Zahlen und einer Lookup-Tabelle

StackOverflow https://stackoverflow.com/questions/1401721

  •  05-07-2019
  •  | 
  •  

Frage

Zur Veranschaulichung, was ich damit meine, hier ist ein Beispiel

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

Ich mag diese Liste und eine Definition von Gruppen zu einer Liste von ganzen Zahlen und einen Lookup-Wörterbuch konvertieren, so dass jedes Element in der Gruppe eine eindeutige ID erhält. Das ID sollte wie folgt in der Lookup-Tabelle auf das Element Karte

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']
}

Ich frage mich, ob es eine elegante und pythonic Lösung für dieses Problem.

Ich bin auch offen für eine bessere Terminologie als create_lookup_list etc

War es hilfreich?

Lösung

defaultdict mit dem itertools.count().next Verfahren kombiniert ist eine gute Möglichkeit Identifikatoren eindeutige Elemente zuweisen. Hier ist ein Beispiel dafür, wie dies in Ihrem Fall anwenden:

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

Edit:. Beachten Sie, dass count().next wird count().__next__ oder lambda: next(count()) in Python 3

Andere Tipps

Meine ist etwa die gleiche Länge und Komplexität:

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

In Ottos Antwort (oder jemand anderes ist mit Saiten-> id dicts), I ersetzen würde (wenn über Geschwindigkeit obsessing Ihre Sache):

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

durch

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

Das ist besser, weil eine direkte Zuordnung zu jedem Element in der inversen Array direkt ist schneller als das Sortieren.

Hier ist meine eigene Lösung - ich bezweifle, dass es die beste

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

Das ist ein bisschen einfacher und direkter.

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)  

Wenn die Lookups richtige Wörterbücher waren, keine Listen, könnte dies weiter vereinfacht werden.
Machen Sie Ihre „Lookup-Tabelle“ haben die folgende Struktur

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

Und es kann weiter in der Komplexität reduziert werden.

Sie können machen diese Arbeitskopie der Lookups in sie invers ist wie folgt:

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

Hier ist meine Lösung, es ist nicht besser - es ist einfach anders:)

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

Hier ist mein, die innere Funktion läßt mich das Index-Tupel als Generator schreiben.

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top