Skip to content

Commit 6b04291

Browse files
Arnav Soodmbauman
authored andcommitted
Row and Column Iterator for Matrices (#29749)
* first pass, sans tests * add test * refactor a bit * fix eltype to show views * fix whitespace * fix typo * rename [ci skip] * typofix [ci skip] * add eachslice() [ci skip] * eachcolumn => eachcol and a bit of error handling [ci skip] * feedback * fix whitespace * refactor eachslice; type-stable now? * git feedback * more git feedback * remove default for eachslice * add tests * prune eachrow eachcol exports and newline fix? * typo in exports * update docs for AbstractArray [ci skip] * Update test/arrayops.jl Co-Authored-By: arnavs <[email protected]> * Update base/abstractarraymath.jl Co-Authored-By: arnavs <[email protected]> * bikeshedding * Add missing backticks and improve message [ci skip] * add exports for eachcol, eachrow [ci skip]
1 parent 15ce5ef commit 6b04291

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

base/abstractarraymath.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,3 +407,40 @@ _reperr(s, n, N) = throw(ArgumentError("number of " * s * " repetitions " *
407407

408408
return R
409409
end
410+
411+
"""
412+
eachrow(A::AbstractVecOrMat)
413+
414+
Create a generator that iterates over the first dimension of vector or matrix `A`,
415+
returning the rows as views.
416+
See also [`eachcol`](@ref) and [`eachslice`](@ref).
417+
"""
418+
eachrow(A::AbstractVecOrMat) = (view(A, i, :) for i in axes(A, 1))
419+
420+
421+
"""
422+
eachcol(A::AbstractVecOrMat)
423+
424+
Create a generator that iterates over the second dimension of matrix `A`, returning the
425+
columns as views.
426+
See also [`eachrow`](@ref) and [`eachslice`](@ref).
427+
"""
428+
eachcol(A::AbstractVecOrMat) = (view(A, :, i) for i in axes(A, 2))
429+
430+
"""
431+
eachslice(A::AbstractArray; dims)
432+
433+
Create a generator that iterates over dimensions `dims` of `A`, returning views that select all
434+
the data from the other dimensions in `A`.
435+
436+
Only a single dimension in `dims` is currently supported. Equivalent to `(view(A,:,:,...,i,:,:
437+
...)) for i in axes(A, dims))`, where `i` is in position `dims`.
438+
See also [`eachrow`](@ref), [`eachcol`](@ref), and [`selectdim`](@ref).
439+
"""
440+
@inline function eachslice(A::AbstractArray; dims)
441+
length(dims) == 1 || throw(ArgumentError("only single dimensions are supported"))
442+
dim = first(dims)
443+
dim <= ndims(A) || throw(DimensionMismatch("A doesn't have $dim dimensions"))
444+
idx1, idx2 = ntuple(d->(:), dim-1), ntuple(d->(:), ndims(A)-dim)
445+
return (view(A, idx1..., i, idx2...) for i in axes(A, dim))
446+
end

base/exports.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,10 @@ export
365365
cumsum!,
366366
accumulate,
367367
accumulate!,
368+
eachcol,
368369
eachindex,
370+
eachrow,
371+
eachslice,
369372
extrema,
370373
fill!,
371374
fill,

test/arrayops.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,22 @@ end
19711971
@test IndexStyle(selectdim(A, 3, 1)) == IndexStyle(view(A, :, :, 1)) == IndexLinear()
19721972
end
19731973

1974+
# row/column/slice iterator tests
1975+
using Base: eachrow, eachcol
1976+
@testset "row/column/slice iterators" begin
1977+
# Simple ones
1978+
M = [1 2 3; 4 5 6; 7 8 9]
1979+
@test collect(eachrow(M)) == collect(eachslice(M, dims = 1)) == [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
1980+
@test collect(eachcol(M)) == collect(eachslice(M, dims = 2)) == [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
1981+
@test_throws DimensionMismatch eachslice(M, dims = 4)
1982+
1983+
# Higher-dimensional case
1984+
M = reshape([(1:16)...], 2, 2, 2, 2)
1985+
@test_throws MethodError collect(eachrow(M))
1986+
@test_throws MethodError collect(eachcol(M))
1987+
@test collect(eachslice(M, dims = 1))[1][:, :, 1] == [1 5; 3 7]
1988+
end
1989+
19741990
###
19751991
### IndexCartesian workout
19761992
###

0 commit comments

Comments
 (0)