Я хотел бы сравнить два отсортированных списков поэлементно и обрабатывать каждый случай по-разному:Python: сравнение двух итерируемыми поэлементно с различным типом
- Если оба итерируемыми содержат элемент, я хотел бы назвать
update_func
. - Если только левый итерируемый содержит элемент, я бы хотел позвонить
left_surplus_func
. - Если только правильный итеративный элемент содержит элемент, я бы хотел позвонить
right_surplus_func
.
К сожалению, zip
не помогает мне в этом случае, так как он создавал кортежи несвязанных элементов. Кроме того, в моем случае оба списка или итерации имеют разные и неконвертируемые типы.
Это похоже на How can I compare two lists in python and return matches и Checking if any elements in one list are in another, но недостаточно близко, чтобы быть реальным решением.
я придумал с рабочим раствором (кроме как итерируемые не должен содержать None
):
def compare_iterables_elemet_wise(left, right, compare_func,
left_surplus_func, update_func, right_surplus_func):
"""
:type left: collections.Iterable[U]
:type right: collections.Iterable[T]
:type compare_func: (U, T) -> int
:type left_surplus_func: (U) -> None
:type update_func: (U, T) -> None
:type right_surplus_func: (T) -> None
"""
while True:
try:
l = next(left)
except StopIteration:
l = None # Evil hack, but acceptable for this example
try:
r = next(right)
except StopIteration:
r = None
if l is None and r is not None:
cmp_res = 1
elif l is not None and r is None:
cmp_res = -1
elif l is None and r is None:
return
else:
cmp_res = compare_func(l, r)
if cmp_res == 0:
update_func(l, r)
elif cmp_res < 0:
left_surplus_func(l)
right = itertools.chain([r], right) # aka right.unget(r)
else:
right_surplus_func(r)
left = itertools.chain([l], left) # aka left.unget(l)
Есть ли более вещий способ архивировать подобный результат? Я немного недоволен своим решением, так как это зависит от внешних побочных эффектов функций. Было бы неплохо иметь чистое функциональное решение.
Edit: Это мой тест:
creates = []
updates = []
deletes = []
def compare(a, obj):
return cmp(int(a), obj)
def handle_left(a):
creates.append(a)
def update(a, obj):
updates.append((a, obj))
def handle_right(obj):
deletes.append(obj)
left = list('12356')
right = [1, 3, 4, 6, 7]
compare_iterables_elemet_wise(iter(left), iter(right), compare, handle_left, update, handle_right)
assert creates == ['2', '5']
assert updates == [('1', 1), ('3', 3), ('6', 6)]
assert deletes == [4, 7]
Я думаю, что мне просто нужно эти три списка: creates
, updates
и deletes
.
Edit2: набор операций:
Это похоже на мою проблему, за исключением того, что типы слева и справа отличаются:
left = [1, 2, 3, 5, 6]
right = [1, 3, 4, 6, 7]
In [10]: set(left) - set(right)
Out[10]: {2, 5}
In [11]: set(right) - set(left)
Out[11]: {4, 7}
In [14]: set(right).intersection(set(left))
Out[14]: {1, 3, 6}
- это два списка с одинаковой длиной? Думаю, не по твоей проблеме? Помогло бы, если бы вы указали простой общий пример вместо своего конкретного кода. –
@ColonelBeauvel: здесь вы идете. –
То, что вы пытаетесь достичь, не является, с моей точки зрения, очевидным ..., поскольку такой набор правил между списками (после преобразования) может помочь в вашей проблеме? –