Or
for (i, item) in pairs(vec)
if you want the indice in the vec with the item
I agree, but, more emphatically: enumerate
is the wrong function, pairs
is the right one, but people always forget it.
Edit: Ah, well, @gustaphe did say ‘counter’, which is alright. I just have a knee-jerk reaction to all the uses of enumerate
.
eachindex
usually improves performance anyways because it uses cartesian directly.
Yeah, I see it the other way, I normally either need the indices or just the items, if I need something together with the items it’s probably a counter.
(Plus, pairs
is so obscure a name I didn’t dare recommending it without double checking)
Oh, that is very different from my experience. I think it’s probably 80-20 that I need pairs
.
Yeah, that’s what I think is a bit sad. Particularly because I very often see enumerate
being used to get indices in the wild.
I would say (as a mnemotechnic) that pairs
is for pairs of (key, value)
, here (index,value)
, while, clearly, enumerate
goes from one
to the end
, so is for a counter.
By the way, for enumerate
it is easy to test for the first iteration ( i == 1)
, but how to test with last iteration ? ( does ( i == end)
works? I do not see how it could). Possibly it is no a real worry, because less frequently interesting that test for first iter, but it arises sometime nevertheless.
On the other side with pairs
you can do ( i == firstindex(v) )
and ( i == lastindex(v) )
, even if it is somewhat verbose?
Comment or suggestions welcome.
If vec
is meant to a traditional (1-indexed) vector, then the “generality” argument should be weighed against the simplicity/portability of length()
.
I believe this trade-off is a bit different for package developers and end-users (especially newcomers to Julia).
Not sure I understand. Is 1:length()
more portable?
As for simplicity, eachindex()
is simpler than 1:length()
, but perhaps less familiar to newcomers. But, once you’ve heard of it, you know it.
Is
1:length()
more portable?
Well, in the sense that it looks pretty similar to what you would do in some of Julia’s competitors.
Absolutely, but there are plenty of reasonable things pairs(vec)
could have meant. I don’t know what I would have wanted it to be called, I just know that I never feel entire certain what pairs
does (or more likely what it’s called).
i == length(vec) && return
That’s a feature. Less risk of off-by-one if you’re translating from eachindex
than from 1:length
.
eachindex
is fine and even for (i, item) in enumerate(vec)
is something that most of us can handle (although it isn’t pretty).
The real problem starts when dealing with matrices (and more). Things like for t = 4:T;i =2:N;x[t,i] = x[t-3,i-1];...
are very easy in traditional notation, but become rather involved when you want to handle OffsetArrays (and what not). I believe this might become a serious hurdle in trying to attract new users.
Thanks all for the discussion!
for c in CartesianIndices(M)
?
btw, enumerate
doesn’t work with OffsetArray because i
starts at 1
in this case, perhaps this:
pairs
doesn’t seem to be compatible with map
the way that enumerate
is… is there an OffsetArrays-compatible alternative to enumerate
that is map
compatible?
Can you show an example of the incompatibility?
enumerate
can be mapped over:
julia> map(enumerate(rand(10))) do (i,x)
(i,x)
end
10-element Vector{Tuple{Int64, Float64}}:
(1, 0.3408824363518682)
(2, 0.052613595813357006)
pairs
can not:
julia> map(pairs(rand(10))) do (i,x)
(i,x)
end
ERROR: map is not defined on dictionaries
Perhaps not as straightforward, but one may define
julia> _pairs(v) = zip(eachindex(v), v)
_pairs (generic function with 1 method)
which can be mapped over:
julia> v = OffsetArray(1:4, 2);
julia> map(_pairs(v)) do x
x
end
4-element OffsetArray(::Vector{Tuple{Int64, Int64}}, 3:6) with eltype Tuple{Int64, Int64} with indices 3:6:
(3, 1)
(4, 2)
(5, 3)
(6, 4)
maybe this helps
function mapover(ints)
isodd(length(ints)) && error("input must be of even length")
xys = Iterators.flatmap(pairs(ints)) do x
x
end
ixs = collect(xys)
twotuples = ((ixs[i], ixs[i+1]) for i=1:2:length(ixs))
collect(twotuples)
end
ints = rand(1:999, 6);
result = mapover(ints);
ints'
# 1×6 adjoint(::Vector{Int64}) with eltype Int64:
# 157 11 305 977 626 989
result
#= 6-element Vector{Tuple{Int64, Int64}}:
(1, 157)
(2, 11)
(3, 305)
(4, 977)
(5, 626)
(6, 989)
=#