2015-12-11 4 views
0

Примечание: Я не уверен, должен ли я задавать этот вопрос здесь или в CodeGolf, поэтому я отправлю его здесь, если это будет уместно.Лямбда-диапазон для петли

Я пытаюсь сделать цикл в Python с использованием лямбды, который имеет следующий формат:

x = 10 
y = range(10) 
w = 2 

for g in range(w*w, x, w): 
    y[g] = 0 

print y 

Это выводит правильный список [0, 1, 2, 3, 0, 5, 0, 7, 0, 9]. Тем не менее, я не могу заставить список изменить, используя lambdas. Мой код таков:

print(lambda w,x=10,y=range(10): (map(lambda g: (lambda f=y.__setitem__: (f(g,0))()), range(w*w,x,w)), y))(2) 

""" 
w is the step value in the for loop, which is 2 
x is the size of the list, 10 
y is the list, range(10) 

lambda g is the first argument for map as the function. It sets the value of the list y at the current index g to be 0, through the use of lambda f's setitem 
range(w*w,x,w) is the second argument passed to map as an iterable. In theory, all the indexes of y in this list should be set to 0 through the use of lambda f 

y is returned to be printed 
2 is the value passed to w 
""" 

Однако это возвращает [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], что является неправильным. Кто-нибудь знает, как я могу добиться этого в одной строке? Должен ли я использовать другие встроенные функции для создания цикла в лямбда? Я использовал this и this для справки, если это помогает.

+0

Есть ли цель сделать это одной линией? Или использовать lambdas для устранения всех конструкций типа for-loop? Можно ли использовать список понятий? – zehnpaard

+0

Предполагалось, что это первое сито с прямой линией. Это лишь часть его. –

+0

Вы не должны так поступать. Это очень плохой код. – shx2

ответ

2

Возможно проще в использовании списковых:

print (lambda w, x=10, y=range(10):\ 
     [(0 if (i >= w*w and i < x and i%w==0) else n) for i, n in enumerate(y)])(2) 

Переехал в две строки для удобства чтения, но вы можете удалить \ и разрыв строки, и он будет работать нормально.

Одно из предостережений заключается в том, что это не изменяет исходный список, а возвращает новый.

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

print (lambda w, x=10, y=range(10):\ 
     ([y.__setitem__(i, 0) for i in range(w*w, x, w)] and y))(2) 

Исправление:

Код выше работает только если range(w*w, x, w) не пусто, т.е. w*w > x, что является слабым условием.

Следующие поправляю для этого выпуска:

print (lambda w, x=10, y=range(10):\ 
     (([y.__setitem__(i, 0) for i in range(w*w, x, w)] or 1) and y))(2) 

Это использует тот факт, что (a or 1) and b всегда оценивают в b после значения a получает оценку.

+0

Что делает 'и y' часть в коде? –

+0

Обычно '(выражение1 и выражение2)' в Python оценивает 'expression2', если' expression1' является Truthy (например, ненулевое число, непустой список и т. Д.) И 'expression1', если' expression1' является Falsy (0, [] и т.д). – zehnpaard

1

Это мерзость использовать map для его побочных эффектов, но:

>>> x = 10 
>>> y = range(10) 
>>> w = 2 
>>> map(lambda i: y.__setitem__(i, 0), range(w*w, x, w)) 
[None, None, None] 
>>> y 
[0, 1, 2, 3, 0, 5, 0, 7, 0, 9] 

Менее нежелательный подход заключается в использовании присваивания ломтика

>>> y = range(10) 
>>> y[w*w: x: w] = [0]*len(range(w*w, x, w)) 
>>> y 
[0, 1, 2, 3, 0, 5, 0, 7, 0, 9] 
+0

В вашем первом примере, как я могу получить y, возвращаясь, напечатав лямбда? –

+0

Вы имеете в виду «print (lambda: (map (lambda i: y .__ setitem __ (i, 0)), диапазон (w * w, x, w)), y) [1])()'? –

+0

Вы можете сделать печать с помощью эффекта sidefffect, подобного этому 'print (map (lambda i: y .__ setitem __ (i, 0), range (w * w, x, w)), y) [1]' –

1

Вот чистый lambda реализации, которая принимает w, x , и y в качестве аргументов для верхнего уровня lambda:

>>> (lambda w,x,y: (lambda s: map(lambda v: 0 if v in s else v, y))(set(range(w*w,x,w))))(2,10,range(10)) 
[0, 1, 2, 3, 0, 5, 0, 7, 0, 9] 
>>> 

Обратите внимание, что это позволяет избежать использования __setitem__.