Reputation: 16065
In Perl I can do something like this to dynamically create an array based on some conditions:
my @arr = (
$foo_defined ? 'foo' : (),
$bar_defined ? 'bar' : (),
$baz_defined ? 'baz' : (),
);
This creates an array of up to 3 elements based on the values of the variables. What would be the closest alternative to this in Python?
Upvotes: 4
Views: 91
Reputation: 27588
Just one more way:
arr = [
*(['foo'] if foo_defined else ()),
*(['bar'] if bar_defined else ()),
*(['baz'] if baz_defined else ()),
]
Upvotes: 0
Reputation: 531035
A close literal translation might be
arr = list(chain(
['foo'] if foo_defined else [],
['bar'] if bar_defined else [],
['baz'] if baz_defined else [],
))
a if b else c
is the Python equivalent of b ? a : c
. chain
concatenates multiple iterable values into a single sequence, similar to how ( (), (), () )
builds an array consisting of array elements (rather than nesting the arrays). list
turns the chain
object into an actual list.
The differing semantics of a Perl array and a Python list make it difficult to do exactly the same thing as tersely as Perl does. Python lacks the ability to have an expression evaluate to nothing to simulate the Perl array handling in your example. (Or put another way, [ [], [], [] ]
in Python creates a list containing 3 empty lists, rather than a single empty list.)
Patrick Artner's answer takes advantage of the fact that a list comprehension can selectively include values from one iterable into the list under construction.
A combination of his and my answers might look like
arr = [s for s in ['foo' if foo_defined else None,
'bar' if bar_defined else None,
'baz' if baz_defined else None] if s is not None]
The difference, though, is that a full list is built first, then a second, final list is built from the first one.
Rolv Apneseth's answer dispenses with a single expression, building the result from an initially empty list and conditionally adding values to it one item at a time. It's terse, but the simulation of Perl-style statement modifiers isn't really idiomatic in Python. Instead, one would just use if
statements:
arr = []
if foo_defined:
arr.append("foo")
if bar_defined:
arr.append("bar")
if baz_defined:
arr.append("baz")
Upvotes: 4
Reputation: 51643
Conditional list comprehension can do it:
defines = [True, False, True]
data = ["foo", "bar", "baz"]
result = [d for defined,d in zip(defines,data) if defined]
print(result)
to get
['foo', 'baz']
zip()
needs same-lenght lists - use iterools.zip_longest if you need some more leeway or defaults.
Upvotes: 2
Reputation: 2118
If I understood correctly (I don't know any Perl I'm afraid), maybe something like this:
foo_defined = True
bar_defined = False
baz_defined = True
arr = []
foo_defined and arr.append("foo")
bar_defined and arr.append("bar")
baz_defined and arr.append("baz")
Output
> print(arr)
['foo', 'baz']
Upvotes: 1