我试图根据条件创建一个列表,其中元素可能存在也可能不存在。例如,如果为 true,则列表为[1, 2, 3]
,否则为[1, 3]
。目前,我可以做的是初始化列表并单独调用.insert
或.append
元素,或者,我可以做类似的事情[1] + ([2] if condition else []) + [3]
,但这很丑陋。
我想知道是否有某种语法,例如[1, 2 if condition, 3]
,但我似乎找不到任何此类语法。有类似的语法吗?
编辑我的列表不是[1, 2, 3]
。我想要一个适用于任何类型对象的通用解决方案,因为我什至不使用数字(这些是 WTForms 验证器)
我也习惯在 Perl 中使用以下模式执行此操作:
my @arr = (1, (condition? (2) : ()), 3);
Run Code Online (Sandbox Code Playgroud)
在Python中,您可以使用与 list 非常接近的解决方案来稍微接近这一点+
,但使用*
解包来避免许多其他数组:
arr = [1, *((2,) if condition else ()), 3]
Run Code Online (Sandbox Code Playgroud)
如果条件为真,可以使用一个产生值的助手来清理它。
T = TypeVar("T")
def cond(val: T, ok: bool) -> Iterable[T]:
if ok:
yield val
arr = [1, *cond(2, condition), 3]
Run Code Online (Sandbox Code Playgroud)
不过,这样做的缺点是不会短路,因此如果创建使用值的成本很高,您可能需要提供一个函数,而不是在条件为真时调用和返回的值。
另一种选择是在构建列表时使用哨兵值并对其进行过滤。可以将其与助手结合起来进行过滤。
class _Ignore: pass
IGNORE = _Ignore()
def cond_list(*elements: Union[T, _Ignore]) -> list[T]:
return [e for e in elements if not isinstance(e, _Ignore)]
arr = cond_list(1, 2 if condition else IGNORE, 3)
Run Code Online (Sandbox Code Playgroud)
如果您想对结果容器类型保持灵活性,您可以选择返回一个可迭代的对象,并将其传递给容器构造函数:
def cond_iter(*elements: Union[T, _Ignore]) -> Iterable[T]:
yield from (e for e in elements if not isinstance(e, _Ignore))
arr = set(cond_iter(1, 2 if condition else IGNORE, 3))
Run Code Online (Sandbox Code Playgroud)
Is this what you're looking for?
[i for i in range(1,4) if i!=2]
UPDATE: based on nice answer above.
Making condition a function instead of a list will generalize it.
def condition(x):
if(x==2):
return False
else:
return True
[i for i in range(1,4) if condition(i)]
Run Code Online (Sandbox Code Playgroud)