I am trying to find out if there is a way to split the value of each iteration of a list comprehension only once but use it twice in the output.
As an example of the problem I am trying to solve is, I have the string:
a = "1;2;4\n3;4;5"
And I would like to perform this:
>>> [(x.split(";")[1],x.split(";")[2]) for x in a.split("\n") if x.split(",")[1] != 5] [('2', '4'), ('4', '5')]
Without the need for running split three times. So something like this (Which is obviously invalid syntax but hopefully is enough to get the message across):
[(x[1],x[2]) for x.split(";") in a.split("\n") if x[1] != 5]
In this question I am not looking for fancy ways to get the 2nd and 3rd column of the string. It is just a way of providing a concrete example. I could for course for the example use:
[x.split(";")[1:3] for x in a.split("\n")]
The possible solutions I have thought of:
csv.DictReader
, name my columns and something like StringIO
to give it the input.This is mostly something that would be a nice pattern to be able to use rather than a specific case so its hard to answer the "why do you want to do this" or "what is this for" kind of questions
Update: After being reading the solution below I went and ran some speed tests. And I found in my very basic tests that the solution provided was 35% faster than the naive solution above.
List comprehensions are also more declarative than loops, which means they're easier to read and understand. Loops require you to focus on how the list is created. You have to manually create an empty list, loop over the elements, and add each of them to the end of the list.
To split the elements of a list in Python: Use a list comprehension to iterate over the list. On each iteration, call the split() method to split each string. Return the part of each string you want to keep.
The split() method splits a string into a list. You can specify the separator, default separator is any whitespace.
Because of differences in how Python implements for loops and list comprehension, list comprehensions are almost always faster than for loops when performing operations.
You could use a list comprehension wrapped around a generator expression:
[(x[1],x[2]) for x in (x.split(";") for x in a.split("\n")) if x[1] != 5]
Starting Python 3.8
, and the introduction of assignment expressions (PEP 572) (:=
operator), it's possible to use a local variable within a list comprehension in order to avoid calling twice the same expression:
In our case, we can name the evaluation of line.split(';')
as a variable parts
while using the result of the expression to filter the list if parts[1]
is not equal to 5
; and thus re-use parts
to produce the mapped value:
# text = '1;2;4\n3;4;5' [(parts[1], parts[2]) for line in text.split('\n') if (parts := line.split(';'))[1] != 5] # [('2', '4'), ('4', '5')]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With