我正在处理一个谜语:
给定一个包含密钥元组的字典:dictionary = {(p,q):n}
,我需要生成每个组合的新字典列表,以便在新字典中既不重复也不重复。在生成此词典列表期间或之后,根据使用字典值的计算,选择其中一个词典作为所需词典。
我的意思的例子(但要小得多):
dictionary = {(1,1): 1.0, (1,2): 2.0, (1,3): 2.5, (1,4): 5.0, (2,1): 3.5, (2,2): 6.0, (2,3): 4.0, (2,4): 1.0}
变为
listofdictionaries = [{(1,1): 1.0, (2,2): 6.0}, {(1,1): 1.0, (2,3): 4.0}, (1,1): 1.0, (2,4): 1.0}, {(1,2): 2.0, (2,1): 3.5}, {(1,2): 2.0, (2,3): 4.0},
等。
字典如:{(1,1): 1.0, (2,1): 3.5}
是不允许的,因为q重复。
现在我的啜泣故事:我对编码很陌生......但我一直在努力编写这个脚本来分析我的一些数据。但我也认为这是一个有趣的算法谜语。我写的东西适用于非常小的字典,但是当我输入一个大字典时,运行时间太长(下面复制)。在我的脚本尝试中,我实际上生成了一个元组组合的列表,而不是我用来在脚本中引用我的主字典。我将在下面复制:
字典元组密钥是使用两个列表生成的:“ExpList1”和“ExpList2”
#first, I generate all the tuple combinations from my ExpDict dictionary
combos =(itertools.combinations(ExpDict,min(len(ExpList1),len(ExpList2))))
#then I generate a list of only the combinations that don't repeat p or q
uniquecombolist = []
for foo in combos:
counter = 0
listofp = []
listofq = []
for bar in foo:
if bar[0] in listofp or bar[1] in listofq:
counter=+1
break
else:
listofp.append(bar[0])
listofq.append(bar[1])
if counter == 0:
uniquecombolist.append(foo)
生成此列表后,我将函数应用于所有字典组合(迭代元组列表并从主字典中调用它们各自的值),并从该函数中选择具有最小结果值的组合。
我还尝试应用函数,同时迭代组合选择唯一的p,q,然后检查结果值是否小于前一个并保留它(如果是)(这不是生成该列表“uniquecombolist “,我最终只生成了最后的元组列表 - 仍然需要很长时间。
我认为解决方案在于在生成组合期间嵌入p,q-no-repeat和最终选择功能。我只是无法绕过如何实际做到这一点。
感谢阅读! 萨拉
编辑:
为了澄清,我写了一个替代我的代码,它将最终函数(基本上是均方根)合并到对的集合中。
`combos =(itertools.combinations(ExpDict,min(len(ExpList1),len(ExpList2))))
prevRMSD = float('inf')
for foo in combos:
counter = 0
distanceSUM = 0
listofp = []
listofq = []
for bar in foo:
if bar[0] in listofp or bar[1] in listofq:
counter=+1
break
else:
listofp.append(bar[0])
listofq.append(bar[1])
distanceSUM = distanceSUM + RMSDdict[bar]
RMSD = math.sqrt (distanceSUM**2/len(foo))
if counter == 0 and RMSD< prevRMSD:
chosencombo = foo
prevRMSD = RMSD`
因此,如果我可以在集合生成期间合并RMS计算并且只保留最小的计算,我认为这将解决我的组合问题。
答案 0 :(得分:1)
这个答案假设您正在尝试使用| S |生成集合元素,其中S是较小的元组坐标池。较大的池将表示为L。
由于该集合将包含| S |没有重复元素的对,S中的每个元素必须恰好出现一次。从这里开始,匹配L的排列,其中| S |使用S的有序元素选择元素。这将生成所有请求的集合详尽且无重复。
注意P(| L |,| S |)等于| L |!/(| L | - | S |)!
根据元组坐标池的大小,枚举的排列可能太多。
复制此枚举的一些代码可能如下所示:
from itertools import permutations
S, L = range(2), range(4) # or ExpList1, ExpList2
for p in permutations(L, len(S)):
print(zip(S, p))
总的来说,您的最终代码可能类似于:
S, L = ExpList1, ExpList2
pairset_maker = lambda p: zip(S, p)
if len(S) > len(L):
S, L = L, S
pairset_maker = lambda p: zip(p, S)
n = len(S)
get_perm_value = lambda p: math.sqrt(sum(RMSDdict[t] for t in pairset_maker(p))**2/n)
min_pairset = min(itertools.permutations(L, n), key=get_perm_value)
如果这不能使您达到所需运行时的一个或两个或两个量级,那么您可能需要考虑一个不能产生最佳解决方案的算法。
答案 1 :(得分:1)
如果我理解你的问题,你会对所有可能的对(p,q)的组合感兴趣,其中p和q与p和q的给定的一组可能值有关。在我的回答中,我假设这些可能的值分别位于list_p
和list_q
中(我认为这是ExpList1
和ExpList2
中的内容,我是对的吗?)< / p>
min_size = min(len(list_p), len(list_q))
combos_p = itertools.combinations(list_p, min_size)
combos_q = itertools.permutations(list_q, min_size)
prod = itertools.product(combos_p, combos_q)
uniquecombolist = [tuple(zip(i[0], i[1])) for i in prod]
如果您正在寻找,请告诉我。顺便欢迎来到SO,很棒的问题!
编辑:
如果您担心列表可能会变得庞大,您可以随时使用生成器表达式并应用您想要的任何函数,例如,
min_size = min(len(list_p), len(list_q))
combos_p = itertools.combinations(list_p, min_size)
combos_q = itertools.permutations(list_q, min_size)
prod = itertools.product(combos_p, combos_q)
uniquecombo = (tuple(zip(y[0], y[1])) for y in prod) # this is now a generator expression, not a list -- observe the parentheses
def your_function(x):
# do whatever you want with the values, here I'm just printing and returning
print(x)
return x
# now prints the minimum value
print(min(itertools.imap(your_function, uniquecombo)))
使用生成器而不是列表时,将根据需要计算值。因为我们对最小值感兴趣,所以每个值都会被计算出来并立即被丢弃,除非它是最小值。