A small package allows indexing array with functions via a simple wrapper FI.
For example, A[FI(iseven)] returns an array containing all elements of A whose indices instead of values are even, like (0:3)[FI(iseven)] == [1, 3].
To access elements whose values are even, try filter(iseven, A).
As a special case, for indexing with !=(i) or !in(I), which are expected to get elements whose index are not is i or not in I,
there is another wrapper not providing a convenient and optimized way.
The not is similar to Not of InvertedIndices, but faster in some cases,
see performance comparing for more information.
1-d indexing A[FI(f)] is equivalent to A[map(f, begin:end)],
multidimensional indexing A[FI(f1), ..., FI(fn)] is equivalent to A[map(FI(f1), axes(A, 1)), ..., map(FI(fn), axes(A, n))].
julia> using FunctionIndices
julia> A = reshape(0:11, 3, 4)
3×4 reshape(::UnitRange{Int64}, 3, 4) with eltype Int64:
0 3 6 9
1 4 7 10
2 5 8 11
julia> A[FI(iseven)]
6-element Vector{Int64}:
1
3
5
7
9
11
julia> A[map(iseven, begin:end)]
6-element Vector{Int64}:
1
3
5
7
9
11
julia> A[FI(isodd), FI(iseven)]
2×2 Matrix{Int64}:
3 9
5 11
julia> A[map(isodd, begin:end), map(iseven, begin:end)]
2×2 Matrix{Int64}:
3 9
5 11not is an alternative to Not, and in most cases they are equivalent:
julia> using InvertedIndices
julia> A[not(1)] == A[Not(1)]
true
julia> A[not(1, 2)] == A[Not(1, 2)]
true
julia> A[not(1:2)] == A[Not(1:2)]
true
julia> let I = rand(Bool, size(A)); A[not(I)] == A[Not(I)] end
trueBut for CartesianIndex and CartesianIndices,
A[not(CartesianIndex(i, j,...))] is equivalent to A[not(i), not(j), ...]
and A[not(CartesianIndices((I, J,...))] is equivalent to A[not(I), not(J), ...],
where not treats inverted Cartesian indices as Cartesian inverted indices,
and always returns an array with the same dimension.
However, A[Not(CartesianIndex(i, j,...))]
converts CartesianIndex to linear index and return a vector,
and A[Not(CartesianIndices((I, J,...)))] seems an undefined behaviour.
julia> A[not(CartesianIndex(1, 2))] # equivalent to A[not(1), not(2)]
2×3 Matrix{Int64}:
1 7 10
2 8 11
julia> A[Not(CartesianIndex(1, 2))] # equivalent to A[Not(3)]
11-element Vector{Int64}:
0
1
2
4
5
⋮
8
9
10
11
julia> A[not(CartesianIndex(1, 2):CartesianIndex(2, 3))] # equivalent to A[not(1:2), not(2:3)]
1×2 Matrix{Int64}:
2 11
julia> A[Not(CartesianIndex(1, 2):CartesianIndex(2, 3))] # seems an undefined behavior
1×2 Matrix{Int64}:
5 8Besides, for out of bounds index like A[4, 5],
A[not(4), not(5)] is equivalent to A[:, :],
because inbounds indices are not equal to the given value,
while A[Not[4], Not(5)] throws a BoundsError.
This package is also compatible with OffsetArrays:
julia> using OffsetArrays
julia> OA = OffsetArray(A, 2:4, 0:3)
3×4 OffsetArray(reshape(::UnitRange{Int64}, 3, 4), 2:4, 0:3) with eltype Int64 with indices 2:4×0:3:
0 3 6 9
1 4 7 10
2 5 8 11
julia> OA[FI(iseven), FI(iseven)] # OA[[2, 4], [0, 2]]
2×2 Matrix{Int64}:
0 6
2 8
julia> OA[not(2), not(3)] # OA[[3, 4], [0, 1, 2]]
2×3 Matrix{Int64}:
1 4 7
2 5 8