Reputation: 1070
Given a matrix m = [10i+j for i=1:3, j=1:4]
, I can iterate over its rows by slicing the matrix:
for i=1:size(m,1)
print(m[i,:])
end
Is this the only possibility? Is it the recommended way?
And what about comprehensions? Is slicing the only possibility to iterate over the rows of a matrix?
[ sum(m[i,:]) for i=1:size(m,1) ]
Upvotes: 56
Views: 33324
Reputation: 12179
The solution you listed yourself, as well as mapslices
, both work fine. But if by "recommended" what you really mean is "high-performance", then the best answer is: don't iterate over rows.
The problem is that since arrays are stored in column-major order, for anything other than a small matrix you'll end up with a poor cache hit ratio if you traverse the array in row-major order.
As pointed out in an excellent blog post, if you want to sum over rows, your best bet is to do something like this:
msum = zeros(eltype(m), size(m, 1))
for j = 1:size(m,2)
for i = 1:size(m,1)
msum[i] += m[i,j]
end
end
We traverse both m
and msum
in their native storage order, so each time we load a cache line we use all the values, yielding a cache hit ratio of 1. You might naively think it's better to traverse it in row-major order and accumulate the result to a tmp
variable, but on any modern machine the cache miss is much more expensive than the msum[i]
lookup.
Many of Julia's internal algorithms that take a dims
keyword, like sum(m; dims=2)
, handle this for you.
Upvotes: 68
Reputation: 652
In my case, I could not use the eachrow
iterator, or nested loops, as I needed to zip eachindex
with something else, and iterate over that zip iterator. Hence, I wrote:
ncols = size(m, 2)
for i in eachindex(m)
rowi, coli = fldmod1(i, ncols)
elem = m[rowi, coli]
end
Note that this will only work where eachindex
returns linear indexing. If eachindex
returns an iterator of Cartesian coordinates, you may need to iterate over 1:prod(size(m))
instead.
Upvotes: 0
Reputation: 9346
As of Julia 1.1, there are iterator utilities for iterating over the columns or rows of a matrix. To iterate over rows:
M = [1 2 3; 4 5 6; 7 8 9]
for row in eachrow(af)
println(row)
end
Will output:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
Upvotes: 29
Reputation: 101
According to my experiences, explicit iterations are much faster than comprehensions.
And iterating over columns are also a good advice.
Besides, you can use the new macros @simd and @inbounds to further accelerate it.
Upvotes: 4