我有兩個串列,每個串列都可以包含重復值,但任何值只能出現在兩個串列中的一個(或沒有)中。
A = [0,1]
B = [2,3]
我想獲得這兩個串列之間的所有唯一映射。
assignment(A,B) = [((0,2),(1,3)), ((0,3),(1,2))]
我知道這可以例如使用 itertools.permutations 來完成。但是,兩個串列中的一個/兩個中都可能有重復項,然后這種方法會給我重復項,因為我不關心分配的順序。因為對于每一個可能的任務,我只想找到總距離。
A = [1,1]
B = [2,3]
mapping(A,B) = [((1,2),(1,3)), ((1,3),(1,2))]
期望的輸出是
mapping(A,B) = [((1,2),(1,3))]
如果只是第一個串列重復了,我可以使用 sympy.utilities.iterables.multiset_permutations 來實作。雖然這對我也不起作用,因為它不能很好地與 numba 配合使用
然而,第二個串列也可以重復,即使這樣我也會得到類似的結果
A = [0,1]
B = [3,3]
mapping(A,B) = [((0,3),(1,3)), ((1,3),(0,3))]
期望的輸出是
mapping(A,B) = [((0,3),(1,3))]
理想情況下,我希望代碼能夠與 numba 一起使用。我最好的方法是只產生 A 的所有排列,將它們通過一組過濾掉重復項,然后只做額外的作業來評估 B 上的重復選項嗎?(它不會給出錯誤的結果,只是減慢代碼的速度)
目前我最好的猜測是我必須做
AB = [list(zip(perm, B)) for perm in set(permutations(A, len(B)))]
和
@njit
def permutations(A, k):
"""Calculates permutation of k elements in A. Needed because numba doesnt like itertools"""
r = [[i for i in range(0)]]
for i in range(k):
r = [[a] b for a in A for b in r if (a in b) == False]
return r
并為 B 重復的情況做額外的作業。
編輯:我現在有兩個版本可以提供所需的結果:
set(tuple(sorted(zip(perm, B))) for perm in set(permutations(A, len(B))))
和
set(tuple(sorted(zip(A, p))) for p in permutations(B))
以及產生來自第二個陣列的重復項的先前版本
[zip(perm, B) for perm in set(permutations(A, len(B)))]
我還測驗了哪個版本對于我的具體用例來說是最快的:
from itertools import product, permutations
import timeit
import numpy as np
A = [0,0,1,1]
B = [2,3,3,3]
mem = np.arange(5)
def vers1(A,B,mem):
res = float("inf")
for mapping in set(tuple(sorted(zip(A, p))) for p in permutations(B)):
temp = 0
for a, b in mapping:
temp = abs(mem[a]-mem[b])
res = min(res,temp)
return res
def vers2(A,B,mem):
res = float("inf")
for mapping in set(tuple(sorted(zip(perm, B))) for perm in set(permutations(A, len(B)))):
temp = 0
for a, b in mapping:
temp = abs(mem[a]-mem[b])
res = min(res,temp)
return res
def vers3(A,B,mem):
res = float("inf")
for mapping in [zip(perm, B) for perm in set(permutations(A, len(B)))]:
temp = 0
for a, b in mapping:
temp = abs(mem[a]-mem[b])
res = min(res,temp)
return res
print(vers1(A,B,mem))
print(timeit.timeit("vers1(A,B,mem)",'from __main__ import vers1, A, B,mem'))
print(vers2(A,B,mem))
print(timeit.timeit("vers2(A,B,mem)",'from __main__ import vers2, A, B,mem'))
print(vers3(A,B,mem))
print(timeit.timeit("vers3(A,B,mem)",'from __main__ import vers3, A, B,mem'))
并得到了這個結果:
9
58.46571195700017
9
23.15174284099703
9
28.064288804998796
uj5u.com熱心網友回復:
使用集合洗掉重復項
import itertools as it
A=[0,1]
B=[3,3]
AB = list(set(tuple(zip(A, p)) for p in it.permutations(B)))
uj5u.com熱心網友回復:
您可以獲取 A 和 B 的集合,然后從 itertools 獲取產品
from itertools import product
A = [1,1]
B = [2,3]
result = list(product(set(A), set(B)))
print(result) # prints [(1, 2), (1, 3)]
uj5u.com熱心網友回復:
考慮到兩個串列都有重復項,從將串列的排列映射到另一個串列中過濾結果的重復項確實是最簡單的。
要在保持其順序和計數的同時去除重復元組,您可以將元組的排列轉換為一組凍結的collection.Counter專案集,然后使用Counter.elements將元組計數轉換回元組。
以下是兩個輸入串列中都有重復項的示例:
from itertools import permutations
from collections import Counter
A = [0,0,1,1]
B = [2,3,3,3]
[
tuple(Counter(dict(s)).elements())
for s in {
frozenset(Counter(zip(A, p)).items())
for p in permutations(B)
}
]
這將回傳:
[((0, 3), (0, 2), (1, 3), (1, 3)), ((1, 2), (0, 3), (0, 3), (1, 3))]
演示:https ://replit.com/@blhsing/LongtermNaturalFiletype
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/515883.html
標籤:Python列表组合学
上一篇:回圈遍歷串列以創建dict
