I would make this more explicit personally than a list comprehension. Here is the conversion for Julia:
II = []
for (i, r) in enumerate(g.reactions())
if in("CO", r.reactants) && in("CO2", r.products)
push!(II, i)
end
end
for i in II
println(g.reaction(i).equation)
end
For your second question on g.net_rates_of_progress[II], I think syntax like this should work: g.net_rates_of_progress[II...] although it’s a bit hard to tell without knowing what the data types are.
Hope that helps, let me know if you have any questions!
P.S. Also, not a stupid question at all! List comprehensions can be hard to read which is why I expanded it in my conversion above.
Doesn’t this syntax literally work in Julia if you put parens around (i,r), change single quotes to double quotes, and change and to &&? i.e.
II = [i for (i,r) in enumerate(g.reactions())
if "CO" in r.reactants && "CO2" in r.products]
is valid Julia syntax for a comprehension. (And in is a valid infix operator in Julia too!)
I just noticed that PyCall does not currently overload in for Python objects, which I should probably fix. In the meantime, you can call r.reactants.__contains__("CO") to call the underlying Python __contains__ method (equivalent to Python’s in operator).
The first formulation (TheCedarPrince) is very understandable for me because I am familiar with the separation between the creation of an empty table and the instructions for filling it.
@stevengj: thank you in particular for the last part of your reply which helps me a lot.
II = [i for (i,r) in enumerate(g.reactions())
if "CO" in r.reactants && "CO2" in r.products]
returns:
ERROR: AbstractDict collections only contain Pairs;
Either look for e.g. A=>B instead, or use the `keys` or `values`
function if you are looking for a key or value respectively.
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] in(p::String, a::Dict{Any, Any})
@ Base ./abstractdict.jl:28
[3] (::var"#8#10")(::Tuple{Int64, PyObject})
@ Main ./none:0
[4] iterate
@ ./iterators.jl:472 [inlined]
[5] iterate
@ ./generator.jl:44 [inlined]
[6] grow_to!(dest::Vector{Int64}, itr::Base.Generator{Base.Iterators.Filter{var"#8#10", Base.Iterators.Enumerate{Vector{PyObject}}}, var"#7#9"})
@ Base ./array.jl:860
[7] collect(itr::Base.Generator{Base.Iterators.Filter{var"#8#10", Base.Iterators.Enumerate{Vector{PyObject}}}, var"#7#9"})
@ Base ./array.jl:784
[8] top-level scope
@ REPL[6]:1
If I just do:
II = [i for (i,r) in enumerate(g.reactions())]
The vector is constructed. Since I use gri30.yaml from cantera, there is 325 elements (what is right).
The part:
I still can’t extract the reactions with CO and CO2 (all the reactions of gri30.yaml are displayed), there is a small modification to make on the indices because in Julia we start at 1:
For exemple, if I consider the first reaction in gri30.yaml:
using PyCall
ct = pyimport("cantera")
g = ct.Solution("gri30.yaml")
r = g.reaction(1)
PyObject H + O + M <=> OH + M <ThreeBodyReaction(Arrhenius)>
r.reactants
Dict{Any, Any} with 2 entries:
"H" => 1.0
"O" => 1.0
And, of course, H and O are the keys of the Dict{}
Ah thanks for sharing the data type. This should work better:
II = []
for (i, r) in enumerate(g.reactions())
if in("CO", keys(r.reactants)) && in("CO2", keys(r.products))
push!(II, i)
end
end
for i in II
println(g.reaction(i - 1).equation)
end
Does that solve the problems you were running into?
This is indeed the solution.
I tried to use keys(r.reactants) on the half of the code, i.e. just with “CO” but I missed the push! to fill table II.
Now, everything is clear.
Many thanks to you both, TheCedarPrice and stevengj.
Just to complete our discussion. I tried this (for fun):
II = []
for (i, r) in enumerate(g.reactions())
if "CO" ∈ keys(r.reactants) && "CO2" ∈ keys(r.products)
push!(II, i)
end
end
for i in II
println(g.reaction(i - 1).equation)
end