0

I would like this carried out in a single list comprehension:

for rec in SeqIO.parse(infile2, "fastq"):
    if rec.id+"_RC" in RCList:
        rec.reverse_complement(id=rec.id,description="")
    else:
        rec

This works:

good_reads = ( rec.reverse_complement(id=rec.id,description="") for rec in SeqIO.parse(infile2, "fastq") if rec.id+"_RC" in RCList )

If I put in else into this line there are general invalid syntax errors:

(1) reads = ( rec.reverse_complement(id=rec.id,description="") for rec in SeqIO.parse(infile2, "fastq") if rec.id+"_RC" in RCList rec if not rec.id+"_RC" in RCList)

or the same goes with:

(2) reads = ( rec.reverse_complement(id=rec.id,description="") for rec in SeqIO.parse(infile2, "fastq") if rec.id+"_RC" in RCList else (rec))

Finally, I am using SeqIO to write this to a file

SeqIO.write(good_reads,infile2+".RC.fastq", "fastq")

What is wrong with the above in (1) and (2) ?

Vince
  • 235
  • 6
  • 19
  • possible duplicate of [python one-line list comprehension: if-else variants](http://stackoverflow.com/questions/17321138/python-one-line-list-comprehension-if-else-variants) – shx2 Jul 07 '14 at 04:59

1 Answers1

2

List comprehensions, and generator expressions, can be a little bit confusing because they use the keyword if but it's not the same as the usual if in Python.

Listcomps and genexps have this format:

expression for x in iterable if condition

The if condition part will be evaluated, and if the result is true, the expression part will be evaluated and (for a listcomp) the value will appear in the new list; or (for a genexp) the value will appear among the values yielded up. But there is no provision for an else here.

You can do exactly what you want using the ternary if in Python. You can have an expression with this format:

true_expression if condition else false_value

condition will be evaluated. If the result is true, then true_expression will be evaluated and the result returned; if the result of condition is false, then false_value will be evaluated and the result returned. This is all one expression.

Some people think it improves readability to put the ternary if into parentheses:

(true_expression if condition else false_value)

You can use the ternary expression described above as the expression part of your listcomp or genexp.

So, you can use it like so:

good_reads = ( rec.reverse_complement(id=rec.id,description="") if rec.id+"_RC" in RCList else rec for rec in SeqIO.parse(infile2, "fastq")  )

See also:

Is it possible to use 'else' in a python list comprehension?

Community
  • 1
  • 1
steveha
  • 74,789
  • 21
  • 92
  • 117
  • Could have sworn I tried that! Thanks so much for the explanation, very concise. – Vince Jul 07 '14 at 05:20
  • And what if an 'elif' equivalent was used instead of the final else? If I attach an 'if' statement after the 'else' it only yields the else results and not the first if condition. – Vince Jul 07 '14 at 05:48
  • There is no `elif` inside an expression. But! You can do what you want! Note that there are actually three expressions inside the ternary: `true_expression`, `condition`, and `false_expression`. Any one of these can, itself, be a ternary expression. But it will quickly get crazy-looking. You might just make a helper function and put any sort of `if` statements you like inside it, and then just call the helper function: `good_reads = ( helper_function(rec) for rec in SeqIO.parse(infile2, "fastq") )` – steveha Jul 07 '14 at 06:19
  • 1
    Ah, of course. Thanks so much for your help, the program is nice and fast now. – Vince Jul 07 '14 at 19:58