给定任何可迭代,例如:“ABCDEF”
对待它几乎就像数字系统一样:
一个 乙 C d Ë F AA AB AC 广告 AE AF BA BB 公元前 .... FF AAA AAB ....
我如何在此列表中找到i th 成员?有效率,而不是通过所有这些计算。我想在这个列表中找到第十亿个(例如)成员。我正在尝试在python中执行此操作,并且我使用2.4(不是选择)可能是相关的,因为我无法访问itertools。
很好,但不是必需的:解决方案是否可以针对伪 - "mixed radix"系统进行推广?
---结果---
# ------ paul -----
def f0(x, alph='ABCDE'):
result = ''
ct = len(alph)
while x>=0:
result += alph[x%ct]
x /= ct-1
return result[::-1]
# ----- Glenn Maynard -----
import math
def idx_to_length_and_value(n, length):
chars = 1
while True:
cnt = pow(length, chars)
if cnt > n:
return chars, n
chars += 1
n -= cnt
def conv_base(chars, n, values):
ret = []
for i in range(0, chars):
c = values[n % len(values)]
ret.append(c)
n /= len(values)
return reversed(ret)
def f1(i, values = "ABCDEF"):
chars, n = idx_to_length_and_value(i, len(values))
return "".join(conv_base(chars, n, values))
# -------- Laurence Gonsalves ------
def f2(i, seq):
seq = tuple(seq)
n = len(seq)
max = n # number of perms with 'digits' digits
digits = 1
last_max = 0
while i >= max:
last_max = max
max = n * (max + 1)
digits += 1
result = ''
i -= last_max
while digits:
digits -= 1
result = seq[i % n] + result
i //= n
return result
# -------- yairchu -------
def f3(x, alphabet = 'ABCDEF'):
x += 1 # Make us skip "" as a valid word
group_size = 1
num_letters = 0
while 1: #for num_letters in itertools.count():
if x < group_size:
break
x -= group_size
group_size *= len(alphabet)
num_letters +=1
letters = []
for i in range(num_letters):
x, m = divmod(x, len(alphabet))
letters.append(alphabet[m])
return ''.join(reversed(letters))
# ----- testing ----
import time
import random
tries = [random.randint(1,1000000000000) for i in range(10000)]
numbs = 'ABCDEF'
time0 = time.time()
s0 = [f1(i, numbs) for i in tries]
print 's0 paul',time.time()-time0, 'sec'
time0 = time.time()
s1 = [f1(i, numbs) for i in tries]
print 's1 Glenn Maynard',time.time()-time0, 'sec'
time0 = time.time()
s2 = [f2(i, numbs) for i in tries]
print 's2 Laurence Gonsalves',time.time()-time0, 'sec'
time0 = time.time()
s3 = [f3(i,numbs) for i in tries]
print 's3 yairchu',time.time()-time0, 'sec'
次:
s0 paul 0.470999956131 sec
s1 Glenn Maynard 0.472999811172 sec
s2 Laurence Gonsalves 0.259000062943 sec
s3 yairchu 0.325000047684 sec
>>> s0==s1==s2==s3
True
答案 0 :(得分:5)
第三次是魅力:
def perm(i, seq):
seq = tuple(seq)
n = len(seq)
max = n # number of perms with 'digits' digits
digits = 1
last_max = 0
while i >= max:
last_max = max
max = n * (max + 1)
digits += 1
result = ''
i -= last_max
while digits:
digits -= 1
result = seq[i % n] + result
i //= n
return result
答案 1 :(得分:5)
底部的多基数解决方案。
import math
def idx_to_length_and_value(n, length):
chars = 1
while True:
cnt = pow(length, chars)
if cnt > n:
return chars, n
chars += 1
n -= cnt
def conv_base(chars, n, values):
ret = []
for i in range(0, chars):
c = values[n % len(values)]
ret.append(c)
n /= len(values)
return reversed(ret)
values = "ABCDEF"
for i in range(0, 100):
chars, n = idx_to_length_and_value(i, len(values))
print "".join(conv_base(chars, n, values))
import math
def get_max_value_for_digits(digits_list):
max_vals = []
for val in digits_list:
val = len(val)
if max_vals:
val *= max_vals[-1]
max_vals.append(val)
return max_vals
def idx_to_length_and_value(n, digits_list):
chars = 1
max_vals = get_max_value_for_digits(digits_list)
while True:
if chars-1 >= len(max_vals):
raise OverflowError, "number not representable"
max_val = max_vals[chars-1]
if n < max_val:
return chars, n
chars += 1
n -= max_val
def conv_base(chars, n, digits_list):
ret = []
for i in range(chars-1, -1, -1):
digits = digits_list[i]
radix = len(digits)
c = digits[n % len(digits)]
ret.append(c)
n /= radix
return reversed(ret)
digits_list = ["ABCDEF", "ABC", "AB"]
for i in range(0, 120):
chars, n = idx_to_length_and_value(i, digits_list)
print "".join(conv_base(chars, n, digits_list))
答案 2 :(得分:3)
您正在做的是接近从基数10(您的号码)到基数6的转换,ABCDEF是您的数字。唯一的区别是“AA”和“A”是不同的,如果你认为“A”是零位数,这是错误的。
如果你为你的数字添加下一个更大的6的幂,然后使用这些数字进行基数转换到6,最后去掉第一个数字(应该是“B”,即“1”) ,你得到了结果。
我只是想在这里发表一个想法,而不是一个实现,因为这个问题很像我的作业(我确实给了怀疑的好处;这只是我的感觉)。
答案 3 :(得分:2)
首先通过总计6的幂来计算长度,直到超过指数(或更好地使用几何系列的公式)。
从索引中减去较小权力的总和。
将表示计算为基数6,填充前导零并映射0 - &gt; A,...,5 - &gt; F。
答案 4 :(得分:2)
这是有效的(也是我最终确定的),并认为它值得发布,因为它很整洁。然而,它比大多数答案慢。我可以在同一个操作中执行%和/吗?
def f0(x, alph='ABCDE'):
result = ''
ct = len(alph)
while x>=0:
result += alph[x%ct]
x /= ct-1
return result[::-1]
答案 5 :(得分:1)
alphabet = 'ABCDEF'
def idx_to_excel_column_name(x):
x += 1 # Make us skip "" as a valid word
group_size = 1
for num_letters in itertools.count():
if x < group_size:
break
x -= group_size
group_size *= len(alphabet)
letters = []
for i in range(num_letters):
x, m = divmod(x, len(alphabet))
letters.append(alphabet[m])
return ''.join(reversed(letters))
def excel_column_name_to_idx(name):
q = len(alphabet)
x = 0
for letter in name:
x *= q
x += alphabet.index(letter)
return x+q**len(name)//(q-1)-1
答案 6 :(得分:1)
由于我们将从数字Base(10)转换为数字Base(7),同时避免输出中的所有“0”,我们将不得不调整原始数字,所以我们每次结果包含“0”时都要跳过。
1 => A, or 1 in base [0ABCDEF]
7 => AA, or 8 in base [0ABCDEF]
13 => BA, or 15 in base [0ABCDEF]
42 => FF, or 48 in base [0ABCDEF]
43 =>AAA, or 50 in base [0ABCDEF]
这是一些Perl代码,显示了我正在尝试解释的内容 (抱歉,没看到这是Python请求)
use strict;
use warnings;
my @Symbols=qw/0 A B C D E F/;
my $BaseSize=@Symbols ;
for my $NR ( 1 .. 45) {
printf ("Convert %3i => %s\n",$NR ,convert($NR));
}
sub convert {
my ($nr,$res)=@_;
return $res unless $nr>0;
$res="" unless defined($res);
#Adjust to skip '0'
$nr=$nr + int(($nr-1)/($BaseSize-1));
return convert(int($nr/$BaseSize),$Symbols[($nr % ($BaseSize))] . $res);
}
答案 7 :(得分:0)
在perl中,您只需将输入i从base(10)转换为base(长度为“ABCDEF”),然后执行与tr/012345/ABCDEF/
相同的y/0-5/A-F/
。当然,Python有一个类似的功能集。
哦,正如Yarichu指出的那样,组合有点不同,因为如果A代表0,那么就没有领先A的组合(尽管他说它有点不同)。我觉得这个问题比实际上更加微不足道。您不能只是音译不同的基数,因为包含等价于0的数字将是 跳过序列。
所以我建议的实际上只是starblue建议的最后一步,这基本上是Laurence Gonsalves实现的ftw。哦,Python中没有音译(tr//
或y//
),真是太遗憾了。