我想得到一个列表的交集,其中没有消除重复项。 我希望该方法是不使用循环的快速方法。 下面是我的尝试,但是此方法失败了,因为删除了重复项。
a = ['a','b','c','f']
b = ['a','b','b','o','k']
tmp = list(set(a) & set(b))
>>>tmp
>>>['b','a']
我希望结果为['a', 'b', 'b']
。
在此方法中,'a'
是固定值,而'b'
是可变值。
还有从'a'
中提取'b'
值的概念。
有没有一种方法可以提取不删除重复值的交叉值列表?
答案 0 :(得分:2)
一个解决方案可能是
good = set(a)
result = [x for x in b if x in good]
这里有两个循环;一个是set
的集合建立循环(在C中实现,比在Python中执行的速度快一百倍),另一个是理解力,并在解释器中运行。
进行第一个循环是为了避免在a
中对b
的每个元素进行线性搜索(如果a
变大,则可能是一个严重的问题)。
请注意,使用filter
可能不会带来太多收益(如果有的话),因为尽管filter
循环位于C中,但对于每个元素,它都必须返回到解释器进行调用过滤功能。
请注意,如果您关心速度,那么Python可能不是一个好选择……例如,在这里PyPy可能会更好,在这种情况下,只需明确编写最佳算法就可以了(避免重新搜索{{ 1}}(例如您的示例中出现的a
中连续的重复项)
b
当然,在性能优化中,唯一的实际方法是尝试在实际系统上使用真实数据进行测量……随着技术的进步和变得越来越复杂,猜测的作用越来越小。
答案 1 :(得分:1)
>>a = ['a','b','c','f']
>>b = ['a','b','b','o','k']
>>items = set(a)
>>found = [i for i in b if i in items]
>>items
{'f', 'a', 'c', 'b'}
>>found
['a', 'b', 'b']
这应该可以完成您的工作。
答案 2 :(得分:1)
不清楚当执行包含重复元素的列表的交集时如何处理重复项,因为您仅给出了一个测试用例及其预期结果,并且没有解释重复项处理。
根据当前保留重复项的工作方式,公用元素为'a'
和'b'
,交集列表列出'a'
的多重性为1,而'b'
的多重性为2。注意'a'
在两个列表 a 和 b 上都出现一次,但是'b'
在 b 上出现两次。相交列表列出了具有等于 maximum 多重性的元素的多重性的公共元素。
答案是是。但是,可以隐式调用循环-尽管您希望代码不显式使用任何循环语句。但是,该算法将始终是迭代的。
步骤1:创建不包含重复项的交集Intersect
(您已经完成了)。转换为列表以保持索引编制。
步骤2:创建另一个数组IntersectD
。使用Freq
创建一个新变量count
,该变量计算该公共元素的最大出现次数。根据元素Intersect
的使用次数,使用Freq
和Intersect[k]
附加元素Freq[k]
多次。
一个包含3个列表的示例代码为
a = ['a','b','c','1','1','1','1','2','3','o']
b = ['a','b','b','o','1','o','1']
c = ['a','a','a','b','1','2']
intersect = list(set(a) & set(b) & set(c)) # 3-set case
intersectD = []
for k in range(len(intersect)):
cmn = intersect[k]
freq = max(a.count(cmn), b.count(cmn), c.count(cmn)) # 3-set case
for i in range(freq): # Can be done with itertools
intersectD.append(cmn)
>>> intersectD
>>> ['b', 'b', 'a', 'a', 'a', '1', '1', '1', '1']
对于涉及两个以上列表的情况,可以使用更复杂的集合交集和max表达式来计算此公共元素的freq
。如果使用列表列表,则可以使用内部循环来计算freq
。您也可以用How can I count the occurrences of a list item?中的itertools表达式替换内部i循环。
答案 3 :(得分:1)
如果您坚持不明确使用for
,那么它将起作用:
>>> list(filter(a.__contains__, b))
['a', 'b', 'b']
据我所知,不建议直接调用诸如__contains__
之类的魔术方法,因此请考虑以下做法:
>>> list(filter(lambda x: x in a, b))
['a', 'b', 'b']
如果您想将a
中的查找从 O(n)改进为 O(1),则创建一个set
首先:
>>> a_set = set(a)
>>> list(filter(lambda x: x in a_set, b))
['a', 'b', 'b']
答案 4 :(得分:1)
我想它并不比循环快,最后您可能仍然需要循环才能提取结果。反正...
from collections import Counter
a = ['a','a','b','c','f']
b = ['a','b','b','o','k']
count_b = Counter(b)
count_ab = Counter(set(b)-set(a))
count_b - count_ab
#=> Counter({'a': 1, 'b': 2})
res
保留结果,则需要:
[ val for sublist in [ [s] * n for s, n in res.items() ] for val in sublist ]
#=> ['a', 'b', 'b']