2013-07-07 2 views
2

Кортежи кажутся идеальными для сравнения версий (при условии, что в моем случае указаны только числовые элементы). У меня есть два номера версии в виде кортежей, состоящих из целых чисел. Скажем, эти кортежи:Диапазон между двумя кортежами целых чисел?

minver = (1,2,3) 
maxver = (1,2,9) 

есть простой и элегантный способ, чтобы получить «диапазон» от minver до maxver как list? То есть для вышеприведенного случая я хотел бы получить list так:

[(1,2,3), (1,2,4), (1,2,5), (1,2,6), (1,2,7), (1,2,8), (1,2,9)] 

(Примечание: это также хорошо, если последний элемент отсутствует в списке, то есть, если возвращаемый диапазон делает не включать максимум значение.)

range функция явно не работает (ожидает целых чисел), но я также не хочу полагаться на кортежах будучи точно x элементов (х = 3 в приведенном выше случае).

Например, если у меня есть minvertuple(1,) оно должно рассматриваться как (1,0,0) если maxvertuple содержит три значения/элементы (такие, как (1,2,3)).

Любой способ сделать это с помощью pythonic (элегантно)?

+0

Поэтому редактирование задает вопрос: каков диапазон между '(1, 2)' и '(1, 3, 1)' (например) –

+1

@JonClements: aaaah ... now Я понял, что вы имеете в виду ... :) ... очень хороший момент, даже не подумал об этом. Предположим, что для него известен максимум, и предположим, что теперь это '9'. Ваш ответ заставляет меня начать, я * думаю *. Трюк в данный момент. – 0xC0000022L

+1

Я просто настраиваю;) –

ответ

6

ОК - это 2:30 утра, поэтому принцип заключается в том, что вы фиксируете максимальную длину и верхнюю границу любой из версий, а затем рассматриваете это как базу для числа ... Преобразуйте начало и конец в int действовать в качестве диапазона, то есть еще одна функция, чтобы преобразовать обратно в кортеже ... потребуется немного работы, но довольно логичная теория ...

from itertools import izip_longest, chain 

minver = (1, 1, 3) 
maxver = (1, 3, 19) 

def version_range(start, end): 
    start, end = zip(*izip_longest(start, end, fillvalue=0)) 
    base = max(max(chain(start, end)), 9) + 1 
    def _toint(seq, base): 
     return sum(base ** n * val for n, val in enumerate(reversed(seq))) 
    def _totuple(num, base, length): 
     ret = [] 
     for n in (base ** i for i in reversed(range(length))): 
      res, num = divmod(num, n) 
      ret.append(res) 
     return tuple(ret) 
    for se in xrange(_toint(start, base), _toint(end, base) + 1): 
     print _totuple(se, base, len(start)) 


version_range(minver, maxver) 
1

чтобы сделать вещи еще, это 3:00 утра здесь:)

Я думаю, что это можно достичь без мощности ** операций, которые могут стать дорогими для больших чисел.

Я написал этот код для python 3, но он может быть легко принят для python 2.7.

Принцип заключается в том, чтобы просто генерировать новую версию, пока мы не достигнем максимальной.

Вот код:

# Easier to work with lists (for me) 
min_ver = [1,1,2] 
max_ver = [2,3,4] 

max_num = max(min_ver + max_ver) 
orig_length = len(min_ver) 


def increase(an_array, max_num): 
    while an_array[-1] == max_num: 
     an_array.pop() 
    an_array[-1] += 1 
    an_array += [0] * (orig_length - len(an_array)) 
    return an_array 


def gen_range(start, end, max_num): 
    while start != end: 
     yield increase(start, max_num) 


for version in gen_range(min_ver, max_ver, max_num): 
    print(version) 

Некоторые сравнения:

Использование **:

C:\Work>python -mtimeit -s"import tuples2" "tuples2.version_range((1,1,1),(1,3,5));" 

10000 петель, лучше всего 3: микросекунды за петлю

Использование increase:

C:\Work>python -mtimeit -s"import tuples" "tuples.gen_range([1,1,1], [1,3,5], 5)" 

1000000 петли, лучшие из 3: 0.606 usec за цикл

Смежные вопросы