2012-04-17 2 views
-2

У меня есть список B = [0,0,0,0,0,0,0,0,0], но это может быть любая длина.Создание условного итерационного списка

Я пытаюсь выполнить итерацию всех возможных значений, которые я могу поместить в B по итерации. Когда выполняется какое-либо условие C, я хочу «перезагрузить» элемент, который я только что повторил, и надавить на следующий элемент вверх на 1. Тип вроде двоичного:

000 становится 001, но затем, когда мы увеличиваем до 002, условие C является встретились, чтобы мы опустили его до 0 и увеличили следующий столбец: 002 становится 010 и т. д.

Извините, если я это плохо объяснил.

Так B может идти от

B=[0,0,0,0,1,2,5] 
to 
B=[0,0,0,0,1,2,6] 
to 
B=[0,0,0,0,1,2,7] 

и так далее.

Но когда условие C выполняется, я хочу, чтобы сбросить таким образом:

B=[0,0,0,0,1,2,96] 
...attempt to increment 
B=[0,0,0,0,1,2,97] 
...attempt to increment 
Condition C met 
B=[0,0,0,0,1,3,0] 

И быть в состоянии сделать это, пока я в конце концов попал условие С на крайнем левом элементе (эквивалент удара 1111111 и быть больше не может его увеличить).

Ради облегчения кодирования скажем условие C = сумма всех чисел превышает 100.

Моя попытка (в соответствии с просьбой AGF):

B=[0,0,0,0,0,0,0,0] 
lenB=len(B) 

while sum(B)<=100: #I think I have to somehow account for having tried incrementing the far left instead 
    B[lenB-1]+=1 #increment last value in B 
    while sum(B)>100: #if the sum is greater than 100 
     B[lenB-1]=0 #reset the far right element 
     B[lenB-2]+=1 #increment the next element 
     #but this is wrong because it needs to perform this check again and again 
     #for every column, while also checking if B[len-1] or B[len-2] even exists 

EDIT: Мое состояние C в реальность MUCH сложнее, чем просто проверка, если Sum (B)> 100. Я просто использую это как фиктивное условие, потому что я могу просто заменить «если сумма (B)> 100» моей более сложной условной функцией.

+2

Что вы пробовали? Пожалуйста, сообщите нам _специально_ какую часть вы не можете решить и покажите нам свою попытку. Мы не здесь, чтобы написать ваш код для вас. – agf

+0

Я не знаю, как правильно прокручивать процесс и отслеживать, где я, и как я знаю, чтобы увеличить количество вещей.Потому что я думаю, что мне приходится учитывать ситуации, когда мне нужно сбросить сразу несколько вещей, например, как вы могли бы быть в 0111111 и «сбросить» до 1000000. – AOAOne

+0

@agf Я добавил свою попытку выше по запросу – AOAOne

ответ

0

Это делает то, что вы хотите?

B=[0,1,0] 

def check(ll,callback): 
    """ 
    This function only works if you 
    increment the last element in the list. 
    All other incrementing is done in this function. 
    """ 
    for idx in reversed(range(len(ll))): 
     if(callback(ll)): 
      ll[idx]=0 
      ll[idx-1]+=1 
     else: 
      break #this index wasn't updated, so the next one won't be either. 

    #a check to see if every element is 1 
    return all(map(lambda x: x==1,ll)) 

def checksum(ll): 
    return True if sum(ll)>100 else False 

count=0 
while True: 
    count+=1 
    B[-1]+=1 
    if(check(B,checksum)): break 
    print B 

print B # [1,1,1] 
print count 

Даже для этого примера, мы бежим через более чем 5000 итераций, прежде чем [1,1,1]

EDIT

Добавлен простой break заявление, как это нужно только, чтобы проверить пока он изменился во время последней итерации.

+0

Да, это так. Я думаю, что мне просто нужно завершить проверку и B [-1] + = 1 часть внутри цикла. Как я смогу установить конечное конечное условие при попытке обновить левый столбец и не могу сделать это? – AOAOne

+0

Предположительно, последний элемент, который должен быть обновлен, является первым элементом в списке, поэтому после цикла for вы можете проверить, соблюдено ли ваше конечное условие и вернуть какое-либо значение из проверки. – mgilson

+0

Я передумал, теперь, когда он уточнил свой вопрос. Я думаю, что это в основном правильный подход. – agf

0

Вы можете сделать это с помощью списка понимания и range() (используя малые значения здесь, чтобы остановить вывод был очень большой):

>>> [(a, b, c) for a in range(2) for b in range(4) for c in range(3)] 
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 3, 0), (0, 3, 1), (0, 3, 2), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 3, 0), (1, 3, 1), (1, 3, 2)] 

Обратите внимание, что если вы хотите, чтобы петля над ней, а не генерировать большой список в начале, используя выражение генератор создает только предметы по мере необходимости:

for a, b, c in ((a, b, c) for a in range(2) for b in range(4) for c in range(3)): 
    ... 

И обратите внимание, что в Python 2.x, здесь вы хотели бы использовать xrange() вместо range, чтобы получить генераторы, а не списки.

+0

Это будет работать только в том случае, если условия специфичны для цифр. Например. 'B <= 5'. Он не будет работать, например, 'sum (list)> = 100', как в примере. – cmh

+0

@agf Он сказал, что это не домашнее задание, поэтому нет оснований для этого. –

+0

Мое условие C на самом деле намного сложнее суммы (B)> 100, но это фиктивное условие, которое легко проверить, чтобы задать этот вопрос. Моя проблема заключается в правильном увеличении/сбросе списка. – AOAOne

1
def increment(box, condition): 
    # last index in the list 
    maxindex = index = len(box) - 1 
    while True: 
     # so you can see it's correct 
     print box 
     # increment the last digit 
     box[-1] += 1 
     # while the overflow condition is True 
     while condition(box): 
      # reset the current digit 
      box[index] = 0 
      # and move to the next index left 
      index -= 1 
      # if we're past the end of the list 
      if index < 0: 
       # stop 
       return 
      # increment the current digit 
      box[index] += 1 
     # back to the rightmost digit 
     index = maxindex 

increment([0] * 3, lambda box: sum(box) > 4) 
+0

Мне кажется, мне нужно изменить свой вопрос - условие C не зависит от цифр. Он фактически инкапсулирует все элементы B, но я выбрал только «sum (B)> 100», потому что это просто и легко. Легче ли упоминать, что условие C произвольно? – AOAOne

+0

@AOAOne Это не имеет большого значения. Вместо проверки 'if box [index] == maxval' просто проверьте, какое бы ваше состояние не было. Остальная логика такая же. – agf

+0

Пробовал, и он, кажется, повторяет значения и выходит за рамки моего условия перезагрузки. Например, если вы поместите сумму (поле)> 10, она отобразит такие вещи, как [0,0,11] и повторит несколько вещей. – AOAOne

0

Компактное, но неэффективное решение

Если условия не являются цифрами конкретными, попробуйте использовать решение, похожее на LattyWare, но с фильтром, чтобы обеспечить только Предикатные результаты.

Если у вас есть список предикатных функций отображения (a, b, c) в bool

for a, b, c in ((a, b, c) for a in range(2) for b in range(4) for c in range(3)): 
    if all [p(a,b,c) for p in predicates]: 
     yield a, b, c 

Обратите внимание, что это становится несостоятельным, если вы не можете поставить разумную щёток, связанную с отдельными цифрами (поисковые пространства становятся слишком большими) ,

+0

Это не очень хороший метод. Откуда вы знаете, какой размер должны быть диапазоны? В зависимости от предикатов это может быть невероятно неэффективным, потому что подавляющее большинство предметов не будет действительным. С цифровым приращением, если вы знаете, что вам нужно увеличиваться после 5, вы не проверяете 6, 7, 8 и т. Д. – agf

+0

Я согласен, что это потенциально очень неэффективно (и в моем ответе так много сказано). Это, однако, элегантно для времен, когда диапазоны малы. – cmh

+0

Но если предикат очень сложный/недетерминированный, как вы знаете, какие диапазоны должны быть? Для 'sum' max для каждого значения является' sum', но что относительно чего-то более сложного? – agf

0

Это, кажется, для решения вашего увеличивающегося вопроса, как вы ожидали:

b=[0,0,0,0,0,0,0,1,7] 

def incr(arr, condition, pred): 
    arr[-1] += 1 
    element = -1 
    while condition(arr) > pred: 

     if arr[element]: 
     arr[element] = 0 
     arr[element-1] += 1 
     else: 
     element -= 1 
     if abs(element) == len(arr): 
     break 
    return arr 

print b 
for i in xrange(0,10): 
    b = incr(b, sum, 15) 
    print b 

Функции принимает список и функциональное состояние (например, сумму) и точку, где прирост должен наследоваться.

Таким образом, он возвращает результат, как это для примера суммы (15):

>>> 
[0, 0, 0, 0, 0, 0, 0, 1, 7] 
[0, 0, 0, 0, 0, 0, 0, 1, 8] 
[0, 0, 0, 0, 0, 0, 0, 1, 9] 
[0, 0, 0, 0, 0, 0, 0, 1, 10] 
[0, 0, 0, 0, 0, 0, 0, 1, 11] 
[0, 0, 0, 0, 0, 0, 0, 1, 12] 
[0, 0, 0, 0, 0, 0, 0, 1, 13] 
[0, 0, 0, 0, 0, 0, 0, 1, 14] 
[0, 0, 0, 0, 0, 0, 0, 2, 0] 
[0, 0, 0, 0, 0, 0, 0, 2, 1] 
[0, 0, 0, 0, 0, 0, 0, 2, 2] 
3

Edit: я, как представляется, создали решение для другой, более сложной проблемой. Вот мое решение этой проблемы, как осветляет AGF в комментариях:

def uphill(initial=None): 
    """Yields a tuple of integers. On each iteration, add one to the last column 
    . If True is sent then reset the column, and begin iterating the previous 
    column, until the first column is matched.""" 
    b = initial 
    column = len(initial)-1 
    while True: 
     if (yield tuple(b)): 
      b[column] = 0 
      if column > 0: 
       column -= 1 
       b[column] += 1 
      else: 
       yield None 
       raise StopIteration 
      yield None 
     else: 
      b[column] += 1 

gen = uphill([1, 2, 0]) 
for b in gen: 
    print(b) 
    if sum(b) >= 4: 
     gen.send(True) 

Давать нам:

(1, 2, 0) 
(1, 2, 1) 
(1, 3, 0) 
(2, 0, 0) 
(3, 0, 0) 
(4, 0, 0) 

Старое решение:

Мы можем создать очень элегантное решение с генераторы и малоизвестные generator.send():

def waterfall(columns): 
    """Yields a tuple of integers. On each iteration, adds one to the last list 
    item. The consumer can send column numbers to the waterfall during iteration 
    - when this is done, the specified column is reset to 0 and the previous 
    column is incremented. When the first column is reset, the iterator ends.""" 
    b = [0]*columns 
    while True: 
     reset = (yield tuple(b)) 
     if not reset == None: 
      while not reset == None: 
       b[reset] = 0 
       if reset > 0: 
        b[reset-1] +=1 
       else: 
        yield None 
        raise StopIteration 
       reset = (yield None) 
     else: 
      b[-1] += 1 

gen = waterfall(3) 
for b in gen: 
    print(b) 
    if b[2] >= 3: 
     gen.send(2) 
    if b[1] >= 2: 
     gen.send(1) 
    if b[0] >= 1: 
     gen.send(0) 

Что дает нам:

(0, 0, 0) 
(0, 0, 1) 
(0, 0, 2) 
(0, 0, 3) 
(0, 1, 0) 
(0, 1, 1) 
(0, 1, 2) 
(0, 1, 3) 
(0, 2, 0) 
(1, 0, 0) 

Вы могли бы счастливо изменить эти условия, ни к чему. Вы просто посылаете генератору индекс столбца, который вы хотите сбросить (который автоматически увеличивает его над ним на единицу), когда выполняется ваше условие выбора. Когда последний столбец сбрасывается, он заканчивает генератор.

Также стоит отметить, что вы можете использовать gen.close(), чтобы остановить его в любое время, не доходя до конечной колонны. (gen.send(0) - то же, что и gen.close()).

Пример с другим условием:

gen = waterfall(2) 
for b in gen: 
    print(b) 
    if sum(b) >= 3: 
     gen.send(1) 
    if b[0] >= 3: 
     gen.send(0) 

Давать нам:

(0, 0) 
(0, 1) 
(0, 2) 
(0, 3) 
(1, 0) 
(1, 1) 
(1, 2) 
(2, 0) 
(2, 1) 
(3, 0) 
+0

Огромное использование генераторов +1 –

+0

@JakobBowyer Они позволяют вам делать классные вещи. Это также делает синтаксис основного цикла намного лучше - вы можете сосредоточиться на том, что важно, а не на управлении потоком. –

+0

Как бы вы инкапсулировали это для общего случая? Как в ответе моего или в гексапарте? Я не уверен, насколько это полезно, если у вас есть специальный случай сброса - он должен быть в состоянии сказать, какая цифра для сброса, вы просто скажете, нужно ли сбросить или нет. – agf

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