给定两个输入列表,如何创建两个输入共用的元素列表?
例如:对于输入[1,2,3,4,5,6]和[3,5,7,9],结果应该是[3,5];输入[‘这个’,‘这’,' n ', ', ']和[‘这个’,‘不’,‘,’,','],结果应该[‘这个’,‘,’]。
参见: 在Python中,如何从两个列表中找到常用词,同时保持词序?(维持秩序) Python -多个列表的交集?(用于计算>= 3个列表之间的交集) 两个包含重复项的列表的交集?(保持重复元素)
给定两个输入列表,如何创建两个输入共用的元素列表?
例如:对于输入[1,2,3,4,5,6]和[3,5,7,9],结果应该是[3,5];输入[‘这个’,‘这’,' n ', ', ']和[‘这个’,‘不’,‘,’,','],结果应该[‘这个’,‘,’]。
参见: 在Python中,如何从两个列表中找到常用词,同时保持词序?(维持秩序) Python -多个列表的交集?(用于计算>= 3个列表之间的交集) 两个包含重复项的列表的交集?(保持重复元素)
当前回答
我比较了每个答案提到的每一种方法。目前,我使用python 3.6.3来实现这个功能。这是我使用的代码:
import time
import random
from decimal import Decimal
def method1():
common_elements = [x for x in li1_temp if x in li2_temp]
print(len(common_elements))
def method2():
common_elements = (x for x in li1_temp if x in li2_temp)
print(len(list(common_elements)))
def method3():
common_elements = set(li1_temp) & set(li2_temp)
print(len(common_elements))
def method4():
common_elements = set(li1_temp).intersection(li2_temp)
print(len(common_elements))
if __name__ == "__main__":
li1 = []
li2 = []
for i in range(100000):
li1.append(random.randint(0, 10000))
li2.append(random.randint(0, 10000))
li1_temp = list(set(li1))
li2_temp = list(set(li2))
methods = [method1, method2, method3, method4]
for m in methods:
start = time.perf_counter()
m()
end = time.perf_counter()
print(Decimal((end - start)))
如果你运行这段代码,你可以看到如果你使用列表或生成器(如果你迭代生成器,而不是仅仅使用它)。当我强迫生成器打印它的长度时,我这样做了),你会得到几乎相同的性能。但是如果你使用set,你会得到更好的性能。如果你使用交叉方法你会得到更好的性能。在我的电脑中,每种方法的结果如下:
method1: 0.8150673999999999974619413478649221360683441 method2: 0.8329545000000001531148541289439890533685684 method3: 0.0016547000000000089414697868051007390022277 method4: 0.0010262999999999244948867271887138485908508
其他回答
1) Method1 保存list1是字典,然后迭代list2中的每个elem
def findarrayhash(a,b):
h1={k:1 for k in a}
for val in b:
if val in h1:
print("common found",val)
del h1[val]
else:
print("different found",val)
for key in h1.iterkeys():
print ("different found",key)
找到共同和不同的元素:
2) Method2 使用设置
def findarrayset(a,b):
common = set(a)&set(b)
diff=set(a)^set(b)
print list(common)
print list(diff)
使用发电机:
common = (x for x in list1 if x in list2)
这样做的好处是,即使在使用庞大的列表或其他庞大的可迭代对象时,它也会在常数时间内(几乎立即)返回生成器。
例如,
list1 = list(range(0,10000000))
list2=list(range(1000,20000000))
common = (x for x in list1 if x in list2)
对于list1和list2的这些值,这里的所有其他答案都将花费很长时间。
然后,您可以用
for i in common: print(i)
我已经制定出了深度交叉口的完整解决方案
def common_items_dict(d1, d2, use_set_for_list_commons=True, use_set_for_dict_key_commons=True, append_empty=False):
result = {}
if use_set_for_dict_key_commons:
shared_keys=list(set(d1.keys()).intersection(d2.keys())) # faster, order not preserved
else:
shared_keys=common_items_list(d1.keys(), d2.keys(), use_set_for_list_commons=False)
for k in shared_keys:
v1 = d1[k]
v2 = d2[k]
if isinstance(v1, dict) and isinstance(v2, dict):
result_dict=common_items_dict(v1, v2, use_set_for_list_commons, use_set_for_dict_key_commons, append_empty)
if len(result_dict)>0 or append_empty:
result[k] = result_dict
elif isinstance(v1, list) and isinstance(v2, list):
result_list=common_items_list(v1, v2, use_set_for_list_commons, use_set_for_dict_key_commons, append_empty)
if len(result_list)>0 or append_empty:
result[k] = result_list
elif v1 == v2:
result[k] = v1
return result
def common_items_list(d1, d2, use_set_for_list_commons=True, use_set_for_dict_key_commons=True, append_empty=False):
if use_set_for_list_commons:
result_list= list(set(d2).intersection(d1)) # faster, order not preserved, support only simple data types in list values
return result_list
result = []
for v1 in d1:
for v2 in d2:
if isinstance(v1, dict) and isinstance(v2, dict):
result_dict=common_items_dict(v1, v2, use_set_for_list_commons, use_set_for_dict_key_commons, append_empty)
if len(result_dict)>0 or append_empty:
result.append(result_dict)
elif isinstance(v1, list) and isinstance(v2, list):
result_list=common_items_list(v1, v2, use_set_for_list_commons, use_set_for_dict_key_commons, append_empty)
if len(result_list)>0 or append_empty:
result.append(result_list)
elif v1 == v2:
result.append(v1)
return result
def deep_commons(v1,v2, use_set_for_list_commons=True, use_set_for_dict_key_commons=True, append_empty=False):
"""
deep_commons
returns intersection of items of dict and list combinations recursively
this function is a starter function,
i.e. if you know that the initial input is always dict then you can use common_items_dict directly
or if it is a list you can use common_items_list directly
v1 - dict/list/simple_value
v2 - dict/list/simple_value
use_set_for_dict_key_commons - bool - using set is faster, dict key order is not preserved
use_set_for_list_commons - bool - using set is faster, list values order not preserved, support only simple data types in list values
append_empty - bool - if there is a common key, but no common items in value of key , if True it keeps the key with an empty list of dict
"""
if isinstance(v1, dict) and isinstance(v2, dict):
return common_items_dict(v1, v2, use_set_for_list_commons, use_set_for_dict_key_commons, append_empty)
elif isinstance(v1, list) and isinstance(v2, list):
return common_items_list(v1, v2, use_set_for_list_commons, use_set_for_dict_key_commons, append_empty)
elif v1 == v2:
return v1
else:
return None
needed_services={'group1':['item1','item2'],'group3':['item1','item2']}
needed_services2={'group1':['item1','item2'],'group3':['item1','item2']}
result=deep_commons(needed_services,needed_services2)
print(result)
我比较了每个答案提到的每一种方法。目前,我使用python 3.6.3来实现这个功能。这是我使用的代码:
import time
import random
from decimal import Decimal
def method1():
common_elements = [x for x in li1_temp if x in li2_temp]
print(len(common_elements))
def method2():
common_elements = (x for x in li1_temp if x in li2_temp)
print(len(list(common_elements)))
def method3():
common_elements = set(li1_temp) & set(li2_temp)
print(len(common_elements))
def method4():
common_elements = set(li1_temp).intersection(li2_temp)
print(len(common_elements))
if __name__ == "__main__":
li1 = []
li2 = []
for i in range(100000):
li1.append(random.randint(0, 10000))
li2.append(random.randint(0, 10000))
li1_temp = list(set(li1))
li2_temp = list(set(li2))
methods = [method1, method2, method3, method4]
for m in methods:
start = time.perf_counter()
m()
end = time.perf_counter()
print(Decimal((end - start)))
如果你运行这段代码,你可以看到如果你使用列表或生成器(如果你迭代生成器,而不是仅仅使用它)。当我强迫生成器打印它的长度时,我这样做了),你会得到几乎相同的性能。但是如果你使用set,你会得到更好的性能。如果你使用交叉方法你会得到更好的性能。在我的电脑中,每种方法的结果如下:
method1: 0.8150673999999999974619413478649221360683441 method2: 0.8329545000000001531148541289439890533685684 method3: 0.0016547000000000089414697868051007390022277 method4: 0.0010262999999999244948867271887138485908508
这里有一些解决方案是在O(l1+l2)不计算重复项目,而缓慢的解决方案(至少O(l1*l2),但可能更昂贵)确实考虑重复项目。
所以我想我应该添加一个O(l1*log(l1)+l2*(log(l2))解。如果列表已经排序,这尤其有用。
def common_elems_with_repeats(first_list, second_list):
first_list = sorted(first_list)
second_list = sorted(second_list)
marker_first = 0
marker_second = 0
common = []
while marker_first < len(first_list) and marker_second < len(second_list):
if(first_list[marker_first] == second_list[marker_second]):
common.append(first_list[marker_first])
marker_first +=1
marker_second +=1
elif first_list[marker_first] > second_list[marker_second]:
marker_second += 1
else:
marker_first += 1
return common
另一个更快的解决方案包括从list1创建一个item->计数映射,并遍历list2,同时更新映射和计数。不需要排序。需要额外的内存,但技术上是O(l1+l2)