2009-09-23 2 views
1

У меня есть цикл следующего типа:как переписать этот цикл более эффективным способом в Python

a = range(10) 
b = [something] 
for i in range(len(a)-1): 
    b.append(someFunction(b[-1], a[i], a[i+1])) 

Однако для контура убивает много работы. Я пытаюсь написать генератор окон, чтобы дать мне 2 элемента все время, но в конце он все еще требует явного для цикла. Есть ли способ сделать это более коротким и более эффективным в питоническом ключе?

Благодаря

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

ответ

8

Рассмотрим

def make_b(a, seed): 
    yield seed 
    for a,b in zip(a[:-1], a[1:]): 
     seed= someFunction(seed, a, b) 
     yield seed 

, который позволяет делать это

a = xrange(10) 
b= list(make_b(a,something)) 

Обратите внимание, что вы можете часто используют это:

b = make_b(a) 

Вместо фактического создания b в виде списка. b в качестве функции генератора экономит вам значительное время хранения (и некоторое время), потому что вам в действительности не нужен объект list. Часто вам нужно только что-то итеративное.

Аналогичным образом для a. Это не должно быть list, просто что-то итеративное - как функция генератора с оператором yield.

+0

ли это быстрее, чтобы сделать этот список понимание? – leon

+0

Ваше решение полезно, я очень благодарен. Однако я пропустил что-то в оригинальной проблеме. Можете ли вы снова взглянуть на нее? Спасибо, много! – leon

+0

в моем цикле новый элемент b относится к самому b (через b [-1]). С этой целью, я думаю, ваше решение неверно. – leon

4

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

from itertools import tee 

a = range(10) 
a1, a2 = tee(a) 
a2.next() 
b = map(someFunction, a1, a2) 

Что касается расширенной задачи, когда необходимо получить доступ к результату предыдущей итерации - это своего рода внутреннее состояние присутствует в функциональной концепции разворачиваться. Но Python не включает в себя развернутую конструкцию, и по этой причине петли более читабельны в этом случае и, скорее всего, быстрее. Что касается того, чтобы сделать его более Pythonic, я предлагаю поднять парную итерацию на функцию и создать явную переменную цикла.

def pairwise(seq): 
    a, b = tee(seq) 
    b.next() 
    return izip(a, b) 

def unfold_over_pairwise(unfolder, seq, initial): 
    state = initial 
    for cur_item, next_item in pairwise(seq): 
     state = unfolder(state, cur_item, next_item) 
     yield state 

b = [something] 
b.extend(unfold_over_pairwise(someFunction, a, initial=b[-1])) 

Если накладные расходы на переборку действительно являются проблемой, то someFunction должен быть чем-то действительно простым. В этом случае, вероятно, лучше, чтобы написать весь цикл в более быстром языке, такие как С.

2

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

import itertools 

def generate(a, item): 
    a1, a2 = itertools.tee(a) 
    next(a2) 
    for x1, x2 in itertools.izip(a1, a2): 
    item = someFunction(item, x1, x2) 
    yield item 

для использования в качестве:

b.extend(generate(a, b[-1])) 
0

Попробуйте что-то вроде этого:

a = range(10)  
b = [something] 

s = len(b) 
b+= [0] * (len(a) - 1) 
[ b.__setitem__(i, someFunction(b[i-1], a[i-s], a[i-s+1])) for i in range(s, len(b))] 

Также:

  • , используя функцию из itertools должна быть полезна также (ранее сообщения)
  • может быть, вы можете переписать SomeFunction и использовать карту вместо списка понимания
Смежные вопросы