微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从列表列表中选择三个列表的最有效方法,以便所有列表中唯一元素的数量组合大于阈值

如何解决从列表列表中选择三个列表的最有效方法,以便所有列表中唯一元素的数量组合大于阈值

找出是否可以从列表列表中选择三个列表以使所有列表中唯一元素的数量组合大于某个特定数量的最有效方法是什么?我能想出的最佳解决方案是蛮力:

def maximum_number_of_unique_elements(mylist,threshold):
    for a in range(len(mylist)):
        for b in range(a,len(mylist)):
            for c in range(b,len(mylist)):
                if len(set(mylist[a] + mylist[b] + mylist[c])) >= threshold:
                    return True
   return False

示例:

l = [[0,1,2],[0,1],3,6],[3,7],[4,7]]
t = 7

maximum_number_of_unique_elements(l,t) 返回 True,因为通过选择列表 0,2,4 创建了一个带有数字 0,4,6,7 的集合。

解决方法

更简单的解决方案是使用 itertools.combinations_with_replacement,它允许在不更改代码的情况下设置要使用的列表数量(不是每个列表的 for 循环)

from itertools import combinations_with_replacement,chain

def maximum_number_of_unique_elements(values,threshold,nb_list=3):
    for parts in combinations_with_replacement(values,r=nb_list):
        if len(set(chain.from_iterable(parts))) >= threshold:
            return True
    return False

使用 combinations_with_replacement 每个元素都可以重复,使用 combinations 获取唯一元素

print(list(combinations('ABC',r=2)))
# [('A','B'),('A','C'),('B','C')]

print(list(combinations_with_replacement('ABC','A'),('C','C')]
,

一些优化:

def maximum_number_of_unique_elements(mylist,threshold):
    sets = list(map(set,mylist))
    n = len(sets)
    for i,one in enumerate(sets):
        for j in range(i,n):
            two = one | sets[j]
            thresh = threshold - len(two)
            for third in sets[j:]:
                if len(third - two) >= thresh:
                    return True
    return False

基准测试结果:

 7.68 us  original
 8.06 us  azro
 4.49 us  Manuel

 7.77 us  original
 8.01 us  azro
 4.46 us  Manuel

 7.78 us  original
 7.85 us  azro
 4.48 us  Manuel

基准代码:

from timeit import repeat
from functools import partial
from itertools import combinations_with_replacement,chain

def original(mylist,threshold):
    for a in range(len(mylist)):
        for b in range(a,len(mylist)):
            for c in range(b,len(mylist)):
                if len(set(mylist[a] + mylist[b] + mylist[c])) >= threshold:
                    return True
    return False

def azro(values,r=nb_list):
        if len(set(chain.from_iterable(parts))) >= threshold:
            return True
    return False

def Manuel(mylist,n):
            two = one | sets[j]
            thresh = threshold - len(two)
            for third in sets[j:]:
                if len(third - two) >= thresh:
                    return True
    return False

def benchmark(*args):
    solutions = original,azro,Manuel
    number = 10 ** 5
    for _ in range(3):
        for solution in solutions:
            t = min(repeat(partial(solution,*args),number=number)) / number
            print('%5.2f us ' % (t * 1e6),solution.__name__)
        print()
benchmark([[0,1,2],[0,1],3,6],[3,7],[4,7]],7)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。