【发布时间】:2016-09-30 15:22:02
【问题描述】:
我想比较两个排序列表元素并以不同方式处理每种情况:
- 如果两个迭代都包含 an 元素,我想调用
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)
有没有更 Pythonic 的方式来存档类似的结果?我对我的解决方案有点不满意,因为它取决于函数的外部副作用。有一个纯函数式的解决方案会很好。
编辑:这是我的测试用例:
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:给你。
-
在我看来,您尝试实现的不是显而易见的......因为列表之间的 setdiff(转换后)可以帮助解决您的问题?
标签: python list functional-programming itertools iterable