После долгих размышлений я считаю, что Шон МакСоме прав: вы не можете иметь точно то, что вы просили, без "настойчивости" (но см. ** ниже).Проблема в том, что если вы запретите «постоянство», тогда или вы можете иметь несколько ключей, сопоставляемых одному и тому же значению, или , вы можете иметь каждый ключ, и каждое значение появляется только один раз в каждомсписок, но не оба.
Тем не менее, вот класс, который, по-видимому, генерирует именно те ассоциации, которые вам нужны, отличается только от вашего примера тем, что он допускает множественные идентичные значения, если они вводятся как часть одной операции.Я присвоил базовый дизайн ответа lysdexia , используя очереди для управления ситуациями, когда непарный новый ключ сопоставляется с ранее вставленным значением, или наоборот.Есть много проблем с приведенным ниже кодом, но он делает то, что вы просили;и это было забавное упражнение:
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))
Вот как вы его используете, с небольшим расцветом в конце, чтобы показать, что ключи всегда уникальны:
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)
Вот вывод:
(('James', 'Red'),)
(('James', 'Red'), ('John', 'Yellow'), ('Krieg', 'Yellow'))
(('James', 'Red'), ('John', 'Yellow'), ('Krieg', 'Yellow'), ('Sarah', 'Green'), ('Bo-barah', 'Blue'))
** Я поставил настойчивость в кавычки, потому что я думаю, что есть некоторый вопрос относительно того, что на самом деле означает «постоянство», учитывая, что хэши должны быть вычислены ,и единственное постоянство в хеш-таблице - это кэшированное хеш-значение, если оно есть.Я не уверен, что ассоциации в диктовке более "постоянны", чем ассоциации в явно основанном на индексе отображении, таком как это или лиздексия.Они оба на основе индекса, в конце концов, не так ли? Но , я полагаю, что выше будет использовать меньше памяти для больших карт, чем диктант сопоставимого размера.