Python:地图元组的组合

时间:2017-08-25 09:21:56

标签: python list dictionary combinations

我在Python中有一个地图列表,如下所示:

2: a, b
3: b, c, d
4: a

我想创建键值对的所有组合,即:

(2,a)(3,b)(4,a)
(2,a)(3,c)(4,a)
(2,a)(3,d)(4,a)
(2,b)(3,b)(4,a)
(2,b)(3,c)(4,a)
(2,b)(3,d)(4,a)

我既不知道地图的大小也不知道列表的大小,但列表永远不会有超过4个元素。我可以假设密钥是唯一的,但并不是它们总是1,2,3,4或0,1,2,3,如上例所示。

解决这个问题的最聪明/最有效的方法是什么?

3 个答案:

答案 0 :(得分:3)

假设你" dict的列表"使用此格式{2: ["a", "b"], 3: ["b", "c", "d"], 4: ["a"]}(已确认为in comments),您可以先使用列表推导来获取所有可能的键值对,然后使用itertools.product获取组合那些对。

>>> d = {2: ["a", "b"], 3: ["b", "c", "d"], 4: ["a"]}
>>> pairs = [[(k, v) for v in d[k]] for k in d]
>>> list(itertools.product(*pairs))
[((2, 'a'), (3, 'b'), (4, 'a')),
 ((2, 'a'), (3, 'c'), (4, 'a')),
 ((2, 'a'), (3, 'd'), (4, 'a')),
 ((2, 'b'), (3, 'b'), (4, 'a')),
 ((2, 'b'), (3, 'c'), (4, 'a')),
 ((2, 'b'), (3, 'd'), (4, 'a'))]

使用您的"实际"例如:

>>> d = {(8, 5): set(['Mt Everest', 'Mt Blanc']), (11, 5): set(['K2'])}
>>> pairs = [[(k, v) for v in d[k]] for k in d]
>>> list(itertools.product(*pairs))
[(((8, 5), 'Mt Everest'), ((11, 5), 'K2')),
 (((8, 5), 'Mt Blanc'), ((11, 5), 'K2'))]

答案 1 :(得分:1)

首先看基础案例。如果只有一个地图2, a, b,则解决方案为

initial_sol = (2,a) 
              (2,b)

如果我现在再添加一张地图3, b, c, d 通过将新映射中的每个元组附加到先前的解决方案

,可以生成新的解决方案
second_sol = (2,a)(3,b)
             (2,a)(3,c)
             (2,a)(3,d)
             (2,b)(3,b)
             (2,b)(3,c)
             (2,b)(3,d)

现在假设我已经有一个程序为一组给定的地图解决这个问题,通过使用新添加的地图扩展解决方案,可以解决更大地图的问题

import itertools

# supose the maps you want to solve are in this format
themaps=[[2,'a','b'],[3,'b','c','d'],[4,'a']]

# a little work is required to reformat its structure
themaps=list(map(lambda x: list(map(lambda y: (x[0], y), x[1:])),themaps))

def flatmap(func, *iterable):
    return itertools.chain.from_iterable(map(func, *iterable))

# method of appending each element from the newly added map to current solutions 
# in order to extend the old solutions to new solutions of larger maps
def next_solution(sol, anewmap):
  return list(flatmap(lambda x: map(lambda y: x+[y], anewmap), sol))

# a reduced set of maps
def smaller(M): return M[0:-1]

# newly added map
def newmap(M): return M[-1]

# solutions at base case
def base_solution(M): return [[i] for i in M[0]]

# function to solve the problem with any given set of maps
# Notice how this reduces the problem of solving larger maps to smaller maps
def solve_it(allmaps):
    if allmaps == []:
      return []
    elif len(allmaps) == 1:
      return base_solution(allmaps)
    else:
      return next_solution(solve_it(smaller(allmaps)), newmap(allmaps))

print(solve_it(themaps))

答案 2 :(得分:0)

最后想出了一个算法 - 这里是伪代码:

 function comb_map(list)
   if list is empty
       return empty list
   else
       current_element = list.pop()
       result_list = empty list
       for each element in current_list.values #call it: b
         for each element in comb_map(list) #call it: as
           add b to as
           add as to result_list
       return result_list