/ / Idempotent asocjacje asocjacyjne - python, hash

Idempotentowe asocjacje asocjacyjne - python, hash

Mam kilka imion: ["James", "John", "Krieg"] i niektóre kolory: ["Red", "Green", "Blue", "Yellow"]. Chcę zamapować nazwy na kolory, używając funkcji haszowania: f(name) -> color. To powiązanie jest idempotentne. Na przykład, jeśli na oryginalnej liście, f(James) -> Red, po dodaniu nazw lub kolorów do odpowiednich list, f(James) szczątki Red.

Przykład:

Stan listy 1:

["James", "John", "Krieg"] and ["Red", "Green", "Blue", "Yellow"]:
f(James) -> Red
f(John) -> Yellow
f(Krieg) -> Yellow

Stan listy 2:

["James", "John", "Krieg", "Sarah"] and ["Red", "Green", "Blue", "Yellow", "Black"]:
(added "Sarah" and "Black")
f(James) -> Red
f(John) -> Yellow
f(Krieg) -> Yellow
f(Sarah) -> Green

Specyfika funkcji mieszającej nie jestważne tak długo, jak długo próbują jednolitości. Miałem to pytanie, ponieważ mam listę nazw wyświetlanych użytkownikowi, a ponieważ lista ta rośnie, chcę, aby skojarzenia kolorów wcześniej wpisanych nazw były takie same (aby użytkownik zachowywał skojarzenia nazwy / koloru). Zdałem sobie sprawę, że jeśli z góry ustalę listę kolorów, nie będzie to problemem.

Więc teraz jest po prostu z ciekawości - są tamfunkcje mieszania, które nie zmieniają wartości poprzednich asocjacji, ponieważ rozmiary danych wejściowych / wyjściowych rosną, bez trwałości? Przepraszamy za wcześniejsze zamieszanie.

Odpowiedzi:

2 dla odpowiedzi № 1

Powiem, że coś takiego nie istnieje bez polegania na wytrwałości.

Możemy wykluczyć każde mapowanie na podstawie listypozycja. Zacznijmy od N nazw i 1 koloru - oznacza to, że wszystkie nazwy są odwzorowane na jeden kolor. Jeśli później będziemy mieli N nazw i M kolorów, chyba że będziemy w stanie zapamiętać, które nazwy N mapują do tego pierwszego koloru, to nie ma mowy aby to działało.

Podobnie, możemy wykluczyć wszystko na podstawiewartości nazw / kolorów. Załóżmy, że mamy jakąś funkcję f (nazwa, kolor), która zapewnia wynik, dzięki któremu można wybrać najlepszy kolor dla nazwy. Jeśli F (bob, green)> F (bob, red) to kończymy z innym mapowaniem, gdy nasze listy idą od [bob], [red] do [bob], [green, red].

Możesz wymyślić kilka zdegenerowanych rozwiązańdo tego, że nie "jawnie" uratować każde stowarzyszenie ", ale nadal utrzymywać stan wystarczający do odtworzenia obliczeń.Na co najwyżej, przechowywałoby to tyle danych, co po prostu przechowywanie twojego mapowania. W najgorszym razie będą przechowywać o wiele więcej.

Zastosowanie idempotent sugeruje, że twój oryginałpytanie może być abstrakcyjną ciekawostką. Jeśli istnieje konkretny, praktyczny problem, który próbujesz rozwiązać, pomocne byłoby bardziej konkretne wyjaśnienie tego problemu.


2 dla odpowiedzi nr 2

Masz rację, że wystarczy przechowywać skojarzenia w pamięci, czego potrzebujesz, aby taki zestaw skojarzeń był zmienny W pythonie jest to słownik:

>>> assocs = dict(zip(["James", "John", "Krieg", "Sarah"], ["Red", "Green", "Blue", "Yellow"]))
>>> assocs["Sarah"]
"Yellow"
>>> assocs["Sarah"] = "Black"
>>> assocs["Sarah"]
"Black"

EDYTOWAĆ

Jeśli zawsze masz dwie listy i są one zawsze w porządku, to dlaczego nie używać indeksów listy, aby "przechowywać" mapowanie:

>>> names = ["James", "John", "Krieg", "Sarah"]
>>> colors = ["Red", "Green", "Blue", "Yellow"]
>>> def finmap(name):
... i = names.index(name)
... if i < len(colors):
...     return colors[i]
... else:
...     print "all the colors have been assigned"
...

Nadzieja, która pomaga


2 dla odpowiedzi nr 3

Nie jestem do końca pewien, co masz na myśli mówiąc "na bieżąco", ale myślę, że może pomóc idempotentny słownik. Na przykład:

##!/usr/bin/env python
# coding: utf-8

class idempotent_dict(dict):
def __setitem__(self, key, value):
if key in self:
return
super(idempotent_dict, self).__setitem__(key, value)

if __name__ == "__main__":
d = idempotent_dict()

d["James"] = "Red"
d["John"] = "Yellow"
d["Krieg"] = "Yellow"

print d

d["James"] = "Black"
d["John"] = "Red"
d["Sarah"] = "Green"

print d

To drukuje:

{"James": "Red", "John": "Yellow", "Krieg": "Yellow"}
{"Sarah": "Green", "James": "Red", "John": "Yellow", "Krieg": "Yellow"}`

2 dla odpowiedzi № 4

Jeśli rozumiem twoje pytanie, potrzebujesz obiektuktóra pobierze listę kluczy i listę wartości (dowolnej długości lub żadnej) i zwróci słownik, który zawsze ma te same wartości, niezależnie od jakichkolwiek dodatków.

>>> class ListOMatic(object):
def __init__(self):
self.people = []
self.colors = []

def idpt(self, people=[], colors=[]):

for p in people:
if not p in self.people:
self.people.append(p)

for c in colors:
if not c in self.colors:
self.colors.append(c)

return dict(zip(self.people, self.colors))

>>> lom = ListOMatic()
>>> people = ["James", "John", "Krieg"]
>>> colors = ["Red", "Green", "Blue", "Yellow"]
>>> # populate it with our initial values and show that we can pull values out.
>>> print (lom.idpt(people, colors))
{"James": "Red", "John": "Green", "Krieg": "Blue"}
>>> print (lom.idpt())
{"James": "Red", "John": "Green", "Krieg": "Blue"}
>>> print (lom.idpt()["James"])
Red
>>> # add some colors but no names.
>>> print (lom.idpt([],["Purple", "Mauve"]))
{"James": "Red", "John": "Green", "Krieg": "Blue"}
>>> print (lom.idpt())
{"James": "Red", "John": "Green", "Krieg": "Blue"}
>>> # add a name and show that it "picks up" the first available color
>>> print (lom.idpt(["Sarah"],[]))
{"Sarah": "Yellow", "James": "Red", "John": "Green", "Krieg": "Blue"}
>>> print (lom.idpt(["Victor", "Charlie"],["Puce"]))
{"Sarah": "Yellow", "James": "Red", "Charlie": "Mauve", "John": "Green", "Krieg": "Blue", "Victor": "Purple"}
>>> print (lom.idpt())
{"Sarah": "Yellow", "James": "Red", "Charlie": "Mauve", "John": "Green", "Krieg": "Blue", "Victor": "Purple"}
>>> print (lom.idpt()["Sarah"])
Yellow
>>>

Mam nadzieję, że właśnie to rozumiecie "w locie".


2 dla odpowiedzi № 5

Po tym głupio myślę, że Sean McSomething ma rację: nie możesz dokładnie o co prosisz bez "wytrwałości" (ale patrz ** poniżej). Problem polega na tym, że jeśli nie akceptujesz "wytrwałości", to zarówno możesz mieć wiele klawiszy odwzorowujących tę samą wartość, lub możesz mieć każdy klucz i każda wartość pojawia się tylko raz na każdej liście, ale nie obie.

Powiedział, że tutaj jest klasa, która wydaje sięgenerować dokładnie te skojarzenia, które chcesz, różniąc się tylko od twojego przykładu tym, że pozwala na wiele identycznych wartości, o ile są one ponownie wpisane jako część pojedynczej operacji. Odpowiedź lysdexia, używając kolejek do zarządzania sytuacjami, w którychNiesparowany nowy klucz mapuje do wcześniej wstawionej wartości lub odwrotnie. Jest dużo problemów z poniższym kodem, ale robi to, o co prosiłeś; i było to zabawne ćwiczenie:

import itertools

class IdempotentMap(object):
def __init__(self, keys=[], vals=[]):
self.keys = []
self.vals = []
self.keyqueue = []
self.valqueue = []
self.append(keys, vals)

def has_key(self, key):
return key in self.keys or key in self.keyqueue

def has_val(self, val):
return val in self.vals or val in self.valqueue

def append(self, keys=[], vals=[]):
len_diff = len(keys) - len(vals)
if len_diff > 0:
vals.extend([None] * len_diff)
elif len_diff < 0:
keys.extend([None] * abs(len_diff))
seen = set()
for i, k in enumerate(keys):
if k in seen:
keys[i] = None
seen.add(k)
keys = (None if self.has_key(k) else k for k in keys)
vals = (None if self.has_val(v) else v for v in vals)
for key, val in zip(keys, vals):
if key and val:
self.keys.append(key)
self.vals.append(val)
elif key and val is None:
if self.valqueue:
self.keys.append(key)
self.vals.append(self.valqueue.pop(0))
else:
self.keyqueue.append(key)
elif val and key is None:
if self.keyqueue:
self.vals.append(val)
self.keys.append(self.keyqueue.pop(0))
else:
self.valqueue.append(val)

def __iter__(self):
return ((key, val) for key, val in itertools.izip(self.keys, self.vals))

Oto jak z niego korzystać, z odrobiną rozkwitu na końcu, aby pokazać, że klucze są zawsze unikatowe:

idem = IdempotentMap()
idem.append(["James"], ["Red", "Green", "Blue"])
print tuple((key, val) for key, val in idem)
idem.append(["John", "Krieg"], ["Yellow", "Yellow"])
print tuple((key, val) for key, val in idem)
idem.append(["Sarah", "Sarah", "Bo-barah"])
print tuple((key, val) for key, val in idem)

Oto wynik:

(("James", "Red"),)
(("James", "Red"), ("John", "Yellow"), ("Krieg", "Yellow"))
(("James", "Red"), ("John", "Yellow"), ("Krieg", "Yellow"), ("Sarah", "Green"), ("Bo-barah", "Blue"))

** Stawiam wytrwałość w przerażających cytatach, ponieważ myślę, że istnieje pewne pytanie, co właściwie oznacza tutaj "wytrwałość", biorąc pod uwagę, że skróty muszą być obliczony, a jedyną trwałością w tabeli mieszającej jestbuforowana wartość skrótu, jeśli taka istnieje. Nie jestem pewien, czy skojarzenia w dyktaturze są bardziej "trwałe" niż skojarzenia w mapowaniu opartym na indeksie, takim jak ta lub lysdeksja. Oni są obie oparte na indeksie, w końcu, nieprawdaż? Ale, Przypuszczam, że powyższe będzie zużywało mniej pamięci dla dużych map niż dyktatura o porównywalnej wielkości.