개체 목록이 있고 하나를 제외하고 비어있는 모든 개체, using filter
및 lambda
식 을 제거하고 싶습니다 .
예를 들어 입력이 다음과 같은 경우 :
[Object(name=""), Object(name="fake_name"), Object(name="")]
… 출력은 다음과 같아야합니다.
[Object(name=""), Object(name="fake_name")]
lambda
식에 할당을 추가하는 방법이 있습니까? 예를 들면 :
flag = True
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(
(lambda o: [flag or bool(o.name), flag = flag and bool(o.name)][0]),
input
)
답변
:=
Python 3.8에 추가 된 할당 표현식 연산자 는 람다 표현식 내부의 할당을 지원합니다. 이 연산자는 구문상의 이유로 괄호 (...)
, 괄호 [...]
또는 괄호 로 묶인 {...}
표현식 내에 만 나타날 수 있습니다 . 예를 들어 다음과 같이 작성할 수 있습니다.
import sys
say_hello = lambda: (
message := "Hello world",
sys.stdout.write(message + "\n")
)[-1]
say_hello()
Python 2에서는 목록 이해의 부작용으로 로컬 할당을 수행 할 수있었습니다.
import sys
say_hello = lambda: (
[None for message in ["Hello world"]],
sys.stdout.write(message + "\n")
)[-1]
say_hello()
그러나 변수 flag
가의 범위가 아닌 외부 범위에 있기 때문에 예제에서 이들 중 하나를 사용할 수 없습니다 lambda
. 이것은와 관련이 없습니다. 이것은 lambda
Python 2의 일반적인 동작입니다. Python 3를 사용하면 s nonlocal
내부의 키워드 로이 문제를 해결할 수 def
있지만 s 내부에서는 nonlocal
사용할 수 없습니다 lambda
.
해결 방법이 있지만 (아래 참조) 주제를 다루는 동안 …
어떤 경우에는 이것을 사용하여 lambda
.
(lambda: [
['def'
for sys in [__import__('sys')]
for math in [__import__('math')]
for sub in [lambda *vals: None]
for fun in [lambda *vals: vals[-1]]
for echo in [lambda *vals: sub(
sys.stdout.write(u" ".join(map(unicode, vals)) + u"\n"))]
for Cylinder in [type('Cylinder', (object,), dict(
__init__ = lambda self, radius, height: sub(
setattr(self, 'radius', radius),
setattr(self, 'height', height)),
volume = property(lambda self: fun(
['def' for top_area in [math.pi * self.radius ** 2]],
self.height * top_area))))]
for main in [lambda: sub(
['loop' for factor in [1, 2, 3] if sub(
['def'
for my_radius, my_height in [[10 * factor, 20 * factor]]
for my_cylinder in [Cylinder(my_radius, my_height)]],
echo(u"A cylinder with a radius of %.1fcm and a height "
u"of %.1fcm has a volume of %.1fcm³."
% (my_radius, my_height, my_cylinder.volume)))])]],
main()])()
반지름이 10.0cm이고 높이가 20.0cm 인 원통의 부피는 6283.2cm³입니다.
반지름이 20.0cm이고 높이가 40.0cm 인 실린더의 부피는 50265.5cm³입니다.
반지름이 30.0cm이고 높이가 60.0cm 인 실린더의 부피는 169646.0cm³입니다.
하지 마십시오.
… 원래 예제로 돌아가서 : flag
외부 범위 변수에 함수를 사용하여 이전에 할당 된 값을 수정할 수 있습니다.
예를 들어 다음을 사용하여 설정 flag
한 객체 일 수 있습니다 ..value
setattr
flag = Object(value=True)
input = [Object(name=''), Object(name='fake_name'), Object(name='')]
output = filter(lambda o: [
flag.value or bool(o.name),
setattr(flag, 'value', flag.value and bool(o.name))
][0], input)
[Object(name=''), Object(name='fake_name')]
위의 테마에 맞추고 싶다면 setattr
다음 대신 목록 이해력을 사용할 수 있습니다 .
[None for flag.value in [bool(o.name)]]
그러나 실제로 심각한 코드에서는 lambda
외부 할당을 수행 하려는 경우 대신 항상 정규 함수 정의를 사용해야 합니다.
flag = Object(value=True)
def not_empty_except_first(o):
result = flag.value or bool(o.name)
flag.value = flag.value and bool(o.name)
return result
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(not_empty_except_first, input)
답변
filter
/ lambda
표현식 에서 상태를 실제로 유지할 수 없습니다 (전역 네임 스페이스를 남용하지 않는 한). 그러나 reduce()
표현식 에서 전달되는 누적 결과를 사용하여 비슷한 것을 얻을 수 있습니다 .
>>> f = lambda a, b: (a.append(b) or a) if (b not in a) else a
>>> input = ["foo", u"", "bar", "", "", "x"]
>>> reduce(f, input, [])
['foo', u'', 'bar', 'x']
>>>
물론 조건을 약간 조정할 수 있습니다. 이 경우 중복 항목을 필터링하지만 다음을 사용할 수도 있습니다.a.count("")
예를 들어를 사용하여 빈 문자열 만 제한 .
말할 필요도없이, 당신은 이것을 할 수 있지만 정말로해서는 안됩니다. 🙂
마지막으로 순수한 Python으로 무엇이든 할 수 있습니다lambda
. http://vanderwijk.info/blog/pure-lambda-calculus-python/
답변
null을 모두 제거 하고 입력 크기가 변경되면 다시 넣을 수있는 경우 람다를 사용할 필요가 없습니다 .
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = [x for x in input if x.name]
if(len(input) != len(output)):
output.append(Object(name=""))
답변
및 친구들과 다양한 트릭을 수행 할 수는 있지만 표현식 =
내에서는 일반 할당 ( )이 불가능합니다 . lambda
setattr
그러나 문제를 해결하는 것은 실제로 매우 간단합니다.
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(
lambda o, _seen=set():
not (not o and o in _seen or _seen.add(o)),
input
)
당신에게 줄 것입니다
[Object(Object(name=''), name='fake_name')]
보시다시피 마지막 인스턴스 대신 첫 번째 빈 인스턴스를 유지합니다. 대신 마지막이 필요하면로 들어가는 filter
목록을 뒤집고에서 나오는 목록을 뒤집습니다 filter
.
output = filter(
lambda o, _seen=set():
not (not o and o in _seen or _seen.add(o)),
input[::-1]
)[::-1]
당신에게 줄 것입니다
[Object(name='fake_name'), Object(name='')]
한 가지 알아야 할 : 임의의 객체와 작업이 순서대로 해당 개체가 제대로 구현해야 __eq__
하고 __hash__
같은 설명 여기 .
답변
업데이트 :
[o for d in [{}] for o in lst if o.name != "" or d.setdefault("", o) == o]
또는 사용 filter
과 lambda
:
flag = {}
filter(lambda o: bool(o.name) or flag.setdefault("", o) == o, lst)
이전 답변
좋습니다. 필터와 람다를 계속 사용하고 있습니까?
이것은 사전 이해력과 함께 제공되는 것이 더 나을 것 같습니다.
{o.name : o for o in input}.values()
저는 파이썬이 람다에서 할당을 허용하지 않는 이유가 이해에서 할당을 허용하지 않는 이유와 유사하다고 생각합니다. 그리고 그것은 이러한 것들이 C
측면에서 평가 되고 따라서 우리에게 줄 수 있다는 사실 과 관련이 있습니다. 속도 증가. 적어도 귀도의 에세이 중 하나를 읽은 후의 인상입니다. 입니다.
내 생각 엔 이것은 또한 가지고있는 철학에 갈 것입니다 하나의 파이썬에서 어떤 한 가지 일을 올바른 방법.
답변
요약 : 기능적 관용구를 사용할 때는 기능적 코드를 작성하는 것이 좋습니다.
많은 사람들이 지적했듯이 Python에서는 람다 할당이 허용되지 않습니다. 일반적으로 기능적 관용구를 사용할 때 기능적 방식으로 생각하는 것이 좋습니다. 즉, 가능한 한 부작용이나 할당이 없습니다.
다음은 람다를 사용하는 기능적 솔루션입니다. fn
명확성 을 위해 람다를 할당했습니다 (조금 길기 때문에).
from operator import add
from itertools import ifilter, ifilterfalse
fn = lambda l, pred: add(list(ifilter(pred, iter(l))), [ifilterfalse(pred, iter(l)).next()])
objs = [Object(name=""), Object(name="fake_name"), Object(name="")]
fn(objs, lambda o: o.name != '')
당신은 또한 약간의 변화를 통해리스트보다는 이터레이터로이 거래를 할 수 있습니다. 수입품도 약간 다릅니다.
from itertools import chain, islice, ifilter, ifilterfalse
fn = lambda l, pred: chain(ifilter(pred, iter(l)), islice(ifilterfalse(pred, iter(l)), 1))
언제든지 코드를 재구성하여 문의 길이를 줄일 수 있습니다.
답변
대신 flag = True
가져 오기를 대신 할 수 있다면 이것이 기준을 충족한다고 생각합니다.
>>> from itertools import count
>>> a = ['hello', '', 'world', '', '', '', 'bob']
>>> filter(lambda L, j=count(): L or not next(j), a)
['hello', '', 'world', 'bob']
또는 필터가 다음과 같이 더 잘 작성 될 수 있습니다.
>>> filter(lambda L, blank_count=count(1): L or next(blank_count) == 1, a)
또는 가져 오기가없는 단순한 부울의 경우 :
filter(lambda L, use_blank=iter([True]): L or next(use_blank, False), a)