Функция сохранения имеет обратный вызов. Попробуйте использовать это и проверьте, есть ли какая-либо ошибка, которую можно отследить. Вы можете сделать что-то вроде этого.
user.save(function (err) {
if (err) return handleError(err);
// saved!
});
Насколько я могу судить, какое-либо из существующих решений работает над общим одним выстрелом, возможно, бесконечным итератором , все они, похоже, требуют итера способный .
Вот решение.
def batch_by(condition, seq):
it = iter(seq)
batch = [it.next()]
for jump_item in it:
if condition(jump_item):
for item in batch:
yield item, jump_item
batch = []
batch.append(jump_item)
Это будет легко работать на бесконечных итераторах:
from itertools import count, islice
is_prime = lambda n: n == 2 or all(n % div for div in xrange(2,n))
print list(islice(batch_by(is_prime, count()), 100))
Это напечатает первые 100 целых чисел с простым числом, которое следует за ними.
Вот одно простое решение, которое может показаться немного чище:
for i, item in enumerate(items):
for next_item in items[i+1:]:
if some_cond(next_item):
break
# do some stuff with both items
Недостатком является то, что вы проверяете условие для next_item несколько раз. Но вы можете легко оптимизировать это:
cond_items = [item if some_cond(item) else None for item in items]
for i, item in enumerate(items):
for next_item in cond_items[i+1:]:
if next_item is not None:
break
# do some stuff with both items
Однако оба решения несут больше накладных расходов, чем исходное решение из вопроса. И когда вы начнете использовать счетчики для обхода этой проблемы, я думаю, что лучше использовать интерфейс итератора напрямую (как в исходном решении).
Вы можете сделать что-то вроде:
import itertools
def matcher(iterable, compare):
iterator= iter(iterable)
while True:
try: item= iterator.next()
except StopIteration: break
iterator, iterator2= itertools.tee(iterator)
for item2 in iterator2:
if compare(item, item2):
yield item, item2
, но это довольно сложно (и на самом деле не очень эффективно), и было бы проще, если бы вы просто выполнили
items= list(iterable)
, а затем просто напишите два цикла более элементов
.
Очевидно, это не будет работать с бесконечными итерациями, но ваша спецификация может работать только с конечными итерациями.
Вы можете поместить всю итерацию в одну структуру попыток, чтобы было понятнее:
jump_item_iter = (j for j in items if some_cond)
try:
jump_item = jump_item_iter.next()
for item in items:
if jump_item is item:
jump_item = jump_iter.next()
# do lots of stuff with item and jump_item
except StopIteration:
pass
Вы можете написать тело цикла как:
import itertools, functools, operator
for item in items:
jump_item_iter = itertools.dropwhile(functools.partial(operator.is_, item),
jump_item_iter)
# do something with item and jump_item_iter
drop while вернет итератор, который пропускает все те, которые соответствуют условию (здесь « - это элемент
»).
Может быть, уже слишком поздно, но как насчет:
l = [j for j in items if some_cond]
for item, jump_item in zip(l, l[1:]):
# do lots of stuff with item and jump_item
Если l = [j для j в диапазоне (10), если j% 2 == 0], то итерация завершена: [ (0, 2), (2, 4), (4, 6), (6, 8)].
Только итераторы
def(lst, some_cond):
jump_item_iter = (j for j in lst if som_cond(j))
pairs = itertools.izip(lst, lst[1:])
for last in jump_item_iter:
for start, start_next in itertools.takewhile(lambda pair: pair[0] < last, pairs):
yield start, last
pairs = itertools.chain([(start_next, 'dummy')], pairs)
с вводом: range (10) и some_cond = lambda x: x% 2 дает [(0, 1), (1, 3), (2, 3), (3, 5), (4, 5), (5, 7), (6, 7), (7, 9), (8, 9)] (то же, что и ваш пример)
for i in range( 0, len( items ) ):
for j in range( i+1, len( items ) ):
if some_cond:
#do something
#items[i] = item, items[j] = jump_item
Еще лучше использовать itertools.groupby:
def h(lst, cond):
remain = lst
for last in (l for l in lst if cond(l)):
group = itertools.groupby(remain, key=lambda x: x < last)
for start in group.next()[1]:
yield start, last
remain = list(group.next()[1])
Использование: lst = диапазон (10) cond = лямбда x: x% 2 print list (h (lst, cond))
напечатает
[(0, 1), (1, 3), (2, 3), (3, 5), (4, 5), (5, 7), (6, 7), (7, 9), (8, 9)]
Вы в основном пытаетесь сравнить каждый элемент в итераторе с каждым другим элементом в исходном списке?
На мой взгляд, это должно быть так использования двух циклов вместо того, чтобы пытаться уместить их в один.
filtered_items = (j for j in items if some_cond)
for filtered in filtered_items:
for item in items:
if filtered != item:
compare(filtered, item)
Итак, вы хотите сравнить пары элементов в том же списке второй элемент пары должен удовлетворять некоторому условию. Обычно, когда вы хотите сравнить пары в списке, используйте zip
(или itertools.izip
):
for item1, item2 in zip(items, items[1:]):
compare(item1, item2)
Выясните, как вписать ваш some_cond
в этот :)
Как насчет этого?
paired_values = []
for elmt in reversed(items):
if <condition>:
current_val = elmt
try:
paired_values.append(current_val)
except NameError: # for the last elements of items that don't pass the condition
pass
paired_values.reverse()
for (item, jump_item) in zip(items, paired_values): # zip() truncates to len(paired_values)
# do lots of stuff
Если первый элемент элементов совпадает, то он используется как jump_item. Это единственное отличие от исходного кода (и вам может потребоваться такое поведение).
Следующий итератор эффективен по времени и памяти:
def jump_items(items):
number_to_be_returned = 0
for elmt in items:
if <condition(elmt)>:
for i in range(number_to_be_returned):
yield elmt
number_to_be_returned = 1
else:
number_to_be_returned += 1
for (item, jump_item) in zip(items, jump_items(items)):
# do lots of stuff
Обратите внимание, что на самом деле вы можете захотеть установить для первого number_to_be_returned значение 1 ...
Понятия не имею, что вы пытаетесь сделать с этим кодом. Но я на 99% уверен, что все, что бы это ни было, вероятно, можно было бы сделать в 2 строки. У меня также возникает ощущение, что оператор '==' должен быть оператором 'is', иначе что делает функция compare ()? И что произойдет, если элемент, возвращенный вторым вызовом jump_iter.next, также равен элементу? Похоже, алгоритм поступит неправильно, поскольку вы будете сравнивать вторую, а не первую.
Напишите функцию генератора:
def myIterator(someValue):
yield (someValue[0], someValue[1])
for element1, element2 in myIterator(array):
# do something with those elements.
Я понятия не имею, что делает compare ()
, но в 80% случаев вы можете сделать это с помощью простого словаря или пары словарей. Перемещение по списку - это своего рода линейный поиск. Линейный поиск - насколько это возможно - всегда следует заменять либо прямой ссылкой (например, dict), либо поиском по дереву (с использованием модуля bisect).
Мой первый ответ был неправильным, потому что я не совсем понимал, чего вы пытались достичь. Итак, если я правильно понимаю (на этот раз, надеюсь), вы хотите, чтобы основной для элемента в items:
«преследовал» итератор, который отфильтровывает некоторые элементы. Что ж, вы мало что можете сделать, за исключением, может быть, обернуть это в генератор chase_iterator (iterable, some_cond)
, который сделает ваш основной код немного более читаемым.
Может быть, более читаемый подход будет быть "аккумуляторным подходом" (если порядок compare () не имеет значения), например:
others = []
for item in items:
if some_cond(item):
for other in others:
compare(item, other)
others = []
else:
others.append(item)
(чувак, я начинаю ненавидеть Stack Overflow ... слишком затягивает ...)