简体   繁体   English

使用组合复制列表中的项目

[英]Duplicating items in a list with combinations

With two lists in Python: Python 中有两个列表:

i = [0, 1, 2, 3, 4]
j = [1, 4]

I'm trying to duplicate values in j and to get all unique combinations.我正在尝试复制 j 中的值并获取所有唯一组合。 i can be a list of any (hashable) values. i可以是任何(可散列的)值的列表。 It will never contain duplicates, but the order of the values is important.它永远不会包含重复项,但值的顺序很重要。 j is always a subset of i . j始终是i的子集。 Integers are used for example only, the actual values could be strings.整数仅用作示例,实际值可以是字符串。

The output should be: output 应该是:

[
[0, 1, 2, 3, 4], # i is always included as a combination - this can be added independently if required
[0, 1, 1, 2, 3, 4],
[0, 1, 1, 2, 3, 4, 4],
[0, 1, 2, 3, 4, 4]
]

An additional example for clarity:为清楚起见,另一个示例:

i = ["B", "E", "C", "A", "D"]
j = ["C", "A", "D"]

# desired output - the order of i should be preserved
# but the order of lists within the outer list is unimportant
[
["B", "E", "C", "A", "D"], # original list
["B", "E", "C", "C", "A", "D"], # duplicated C
["B", "E", "C", "C", "A", "A", "D"], # duplicated C, A
["B", "E", "C", "C", "A", "D", "D"], # duplicated C, D
["B", "E", "C", "C", "A", "A", "D", "D"], # duplicated C, A, D
["B", "E", "C", "A", "A", "D"], # duplicated A
["B", "E", "E", "C", "A", "A", "D", "D"], # duplicated A, D
["B", "E", "C", "A", "D", "D"], # duplicated D
]

I've tried various list comprehension methods, and a few itertools functions such as product and combination, but have yet to find a satisfactory solution.我尝试了各种列表理解方法,以及一些 itertools 函数,如产品和组合,但还没有找到令人满意的解决方案。

Half-working attempt is as follows, although it is an ugly approach:半工半程的尝试如下,虽然这是一种丑陋的方法:

i = [0, 1, 2, 3, 4]
j = [1, 4]

all_lists = [i]
for x in j:
    new_list = i.copy()
    new_list.insert(i.index(x), x)
    all_lists.append(new_list)

print(all_lists)
# [[0, 1, 2, 3, 4], [0, 1, 1, 2, 3, 4], [0, 1, 2, 3, 4, 4]]
# still missing the [0, 1, 1, 2, 3, 4, 4] case

Background to question - i is a list of nodes in a networkx network, and j a list of nodes with self-loops.问题的背景 - i是 networkx 网络中的节点列表, j是具有自环的节点列表。 The result is a combination of all non-simple paths between the nodes.结果是节点之间所有非简单路径的组合。

You're right to try to use itertools .您尝试使用itertools是对的。 The combinations function is what you want. function combinations就是您想要的。 Just loop over all possible lengths (from 0 to len(j)):只需遍历所有可能的长度(从 0 到 len(j)):

import itertools

i = ["B", "E", "C", "A", "D"]
j = ["C", "A", "D"]

result = []
for l in range(len(j) + 1):
    for j_subset in itertools.combinations(j, l):
        result.append(sorted(i + list(j_subset), key=lambda x: i.index(x)))


print(result)

You said that the lists can contain elements of any type.您说列表可以包含任何类型的元素。 Here is an example of doing the same thing using a custom class Node :这是使用自定义 class Node执行相同操作的示例:

import itertools

# here is my custom Node class
class Node():
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        return self.name == other.name

# the names of the nodes
names_i = ["B", "E", "C", "A", "D"]
names_j = ["C", "A", "D"]


# the actual data we are working with - lists of distinct nodes
i = [Node(name) for name in names_i]
j = [Node(name) for name in names_j]

result = []

for l in range(len(j) + 1):
    for j_subset in itertools.combinations(j, l):
        result.append(sorted(i + list(j_subset), key=lambda x: i.index([node for node in i if node == x][0])))


# print the raw result
print(result)

# print the result but just showing the node names
print([[node.name for node in result_element] for result_element in result])

The key difference with using classes is that two Node classes instantiated with the same name are not the same object, so i.index(x) in your sorted key will not work, since no elements of j are in i (even though they have the same name, and are "equal").使用类的主要区别在于,使用相同名称实例化的两个节点类不是同一个 object,因此sorted键中的i.index(x)将不起作用,因为i中没有j的元素(即使它们有同名,并且“相等”)。 I can explain this more if you like.如果您愿意,我可以对此进行更多解释。

Changed to reflect that j is a list of the values to duplicate更改以反映j是要复制的值的列表

for k in range(len(j) + 1):
    for n in itertools.combinations(j, k):
        lst = i[:]
        for el in n:
            ix = lst.index(el)
            lst.insert(ix, lst[ix])
        print(lst)

EDIT using insert is more efficient than what I had before使用insert进行编辑比我以前的效率更高

Is this what you're looking for?这是你要找的吗?

In [1]: %paste                                                                                                                                                                                                                                                                       
from itertools import combinations

i = [0, 1, 2, 3, 4]
j = [1, 4]

res = []
for r in range(len(j) + 1):
    for comb in combinations(j, r):
        res.append(sorted(i + list(comb)))
print(res)

## -- End pasted text --
[[0, 1, 2, 3, 4], [0, 1, 1, 2, 3, 4], [0, 1, 2, 3, 4, 4], [0, 1, 1, 2, 3, 4, 4]]

In [2]: 

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

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