繁体   English   中英

从列表列表中的每个列表中获取唯一元素

[英]Get unique elements from each list in list of lists

我有一个用整数填充的列表列表。 这些整数表示图中的节点,主列表中的列表表示图中的循环。 我想按照列表列表的顺序提取一组唯一的节点 - 每个循环中的一个节点。

例子:

我知道,不可能有一个只有两个节点的循环,但这是我想出的最简单的不平凡的例子,它应该清楚我在寻找什么。

cycles = [[11, 22, 55], [22, 44], [11, 33], [22, 33]]
result = [11, 44, 33, 22]

另一个可能的结果是[22, 44, 11, 33]

我的解决方案:

到目前为止,我尝试使用itertools.product来遍历列表列表中的所有元素组合,直到找到与主列表中列表数量相同长度的集合。

def find_random_unique_combination_from_cycles(cycles):
    only_one = dict()
    for ci, cy in enumerate(cycles):
        for element in cy:
            if len([element for cyc in cycles if element in cyc]) == 1:
                only_one.update({element: ci})

    prod_cycles = [cycle for ci, cycle in enumerate(cycles) if ci not in only_one.values()]
    cycle_length = len(prod_cycles)
    result = []
    for combi in it.product(*prod_cycles, repeat=1):
        if len(set(combi)) == cycle_length:
            result = list(combi)
            break
    for element, index in only_one.items():
        result.insert(index, element)
    return result

问题:

此解决方案适用于上述示例和类似情况。 但是对于具有更多和更大周期的更大图,它在适当的运行时找不到解决方案(我不得不停止执行包含约 200 个周期的列表)。 我还尝试通过删除只有一个唯一元素的所有循环来减小列表列表的大小,但这并没有太大帮助。 是否有更好更快的方法从每个列表列表中找到单个唯一元素?

非常感谢您的帮助! 提前致谢!

cycles = [[11, 22], [22, 44], [11, 33], [22, 33]]
from itertools import product
a=list(product(*cycles))
[list(i) for i in a if len(i) == len(set(i))]

Output:

[[11, 44, 33, 22], [22, 44, 11, 33]]

如果您想提高效率,可以查看networkx模块。

import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()
cycles = [(11, 22), (22, 44), (11, 33), (22, 33)]
G.add_edges_from(cycles)
nx.draw(G, with_labels=True, font_weight='bold')
G.nodes

图表

G.nodes返回NodeView((11, 22, 44, 33))

我建议使用递归生成器方法将使用的数字集带到下一个递归级别:

def getPath(cycles,used=None):
    if not cycles: yield [];return  # end of path
    if used is None: used = set()   # track used numbers
    for n in cycles[0]:             # take from first sub list
        if n in used: continue      # skip used, recurse, tagging used n
        yield from ([n]+p for p in getPath(cycles[1:],used|{n}))

output:

cycles = [[11, 22, 55], [22, 44], [11, 33], [22, 33]]

for path in getPath(cycles): print(path)

[11, 44, 33, 22]
[22, 44, 11, 33]
[55, 22, 11, 33]
[55, 44, 11, 22]
[55, 44, 11, 33]
[55, 44, 33, 22]

如果您希望路径随机出现,您可以在 function 的开头添加这一行(并导入随机模块):

if used is None: cycles = [random.sample(c,len(c)) for c in cycles]

这将允许您使用 next() function 来获得随机路径,而不必通过所有组合获得 go:

randomPath = next(getPath(cycles))

请注意,生成器使用简单的蛮力遍历。 有优化的空间。

例如,可以检查循环中不同的未使用数字是否足以覆盖子列表的数量。 这将允许更早地短路遍历分支。

...
if len(set().union(*cycles)-used)<len(cycles): return
for n in cycles[0]:
    ...

或者,可以从每个递归级别的循环列表中删除使用的数字。

def getPath(cycles):
    if not cycles: yield [];return  # end of path
    if not all(cycles): return      # no path when there is an empty sublist
    for n in cycles[0]:             # take from first sub list
        nextCycles = [ [r for r in c if r!=n] for c in cycles[1:] ]
        yield from ( [n] + p for p in getPath(nextCycles) )

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM