我正在尝试开发一种方法,用于在以下列表中查找特定序列的有序排名。
a = list(sorted(itertools.combinations(range(0,5),3)))
b = list(sorted(itertools.permutations(range(0,5),3)))
a
表示combinatorial number system的元素列表,因此排名公式非常简单。
我需要的是2个具有以下定义的函数magic_rank_1和magic_rank_2
def magic_rank_1(perm_item,permutation_list_object):
## permutation_list_object is actually b
return list_object.index(perm_item)
def magic_rank_2(perm_item,permutation_list_object,combination_list_object):
## permutation_list_object is actually b and combination_list_object is actually a
return combination_list_object.index(tuple(sorted(perm_item)))
基本上magic_rank_2((0,1,2),b,a) = magic_rank_2((2,0,1),b,a)
听起来很简单..但我有一些限制。
我知道magic_rank_1可以通过与this类似的东西来计算但是有区别,输入字母表中的每个字母都被使用,在我的情况下它是一个子集
最后是的,这应该是散列函数的替代品,目前使用散列函数,但我没有利用magic_rank_2((0,1,2),b,a) = magic_rank_2((2,0,1),b,a)
的事实。如果我可以,它将显着减少我的存储空间需求,因为我的序列的长度实际上是5,所以如果我可以计算magic_rank_2的方法,我将我的存储需求减少到当前需求的1%
更新 - 对于magic_rank_2,元组的元素之间不应该进行比较操作,即没有排序,最小值,最大值等
只会使算法的效率低于常规散列
答案 0 :(得分:0)
以下两个函数将给出一个组合和排列,给定一个单词和一个字母(或者在你的情况下,一个元组和一个列表)。
import itertools
import math
def rank_comb(word, alph, depth=0):
if not word: return 0
if depth == 0:
word = list(word)
alph = sorted(alph)
pos = 0
for (i,c) in enumerate(alph):
if c == word[0]:
# Recurse
new_word = [x for x in word if x != c]
new_alph = [x for x in alph if x > c]
return pos + rank_comb(new_word, new_alph, depth+1)
else:
num = math.factorial(len(alph)-i-1)
den = math.factorial(len(alph)-i-len(word)) * math.factorial(len(word)-1)
pos += num // den
def rank_perm(word, alph, depth=0):
if not word: return 0
if depth == 0:
word = list(word)
alph = sorted(alph)
pos = 0
for c in alph:
if c == word[0]:
# Recurse
new_word = [x for x in word if x != c]
new_alph = [x for x in alph if x != c]
return pos + rank_perm(new_word, new_alph, depth+1)
else:
num = math.factorial(len(alph)-1)
den = math.factorial(len(alph)-len(word))
pos += num // den
#== Validation =====================================================================
# Params
def get_alph(): return range(8)
r = 6
a = list(sorted(itertools.combinations(get_alph(), r)))
b = list(sorted(itertools.permutations(get_alph(), r)))
# Tests
PASS_COMB = True
PASS_PERM = True
for (i,x) in enumerate(a):
j = rank_comb(x, get_alph())
if i != j:
PASS_COMB = False
print("rank_comb() FAIL:", i, j)
for (i,x) in enumerate(b):
j = rank_perm(x, get_alph())
if i != j:
PASS_PERM = False
print("rank_perm() FAIL:", i, j)
print("rank_comb():", "PASS" if PASS_COMB else "FAIL")
print("rank_perm():", "PASS" if PASS_PERM else "FAIL")
功能类似,但差异很小:
new_alph
的过滤方式不同。num
和den
的计算方式不同。更新
rank_comb2
不需要对输入词进行排序(3元组):
import itertools
import math
def rank_comb2(word, alph, depth=0):
if not word: return 0
if depth == 0:
word = list(word)
alph = sorted(alph)
pos = 0
for (i,c) in enumerate(alph):
if c == min(word):
# Recurse
new_word = [x for x in word if x != c]
new_alph = [x for x in alph if x > c]
return pos + rank_comb2(new_word, new_alph, depth+1)
else:
num = math.factorial(len(alph)-i-1)
den = math.factorial(len(alph)-i-len(word)) * math.factorial(len(word)-1)
pos += num // den
r1 = rank_comb2([2,4,1], range(5))
r2 = rank_comb2([1,4,2], range(5))
r3 = rank_comb2([4,1,2], range(5))
print(r1, r2, r3) # 7 7 7