Skip to content

Commit efd8cc6

Browse files
committed
Multi-symbol indexing. Closes #71. Closes #129.
1 parent 5a81362 commit efd8cc6

File tree

8 files changed

+64
-2
lines changed

8 files changed

+64
-2
lines changed

NEWS.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
11
# ComponentArrays.jl NEWS
22
Notes on new features (minor releases). For more details on bugfixes and non-feature-adding changes (patch releases), check out the [releases page](https://github.com/jonniedie/ComponentArrays.jl/releases).
33

4+
### v0.12.0
5+
- Multiple symbol indexing!
6+
- Use either an `Array` or `Tuple` of `Symbol`s to extract multiple named components into a new `ComponentArray
7+
- It's fast!
8+
```julia
9+
julia> ca = ComponentArray(a=5, b=[4, 1], c=(a=2, b=[6, 30.0]))
10+
ComponentVector{Float64}(a = 5.0, b = [4.0, 1.0], c = (a = 2.0, b = [6.0, 30.0]))
11+
12+
julia> ca[(:c, :a)]
13+
ComponentVector{Float64}(c = (a = 2.0, b = [6.0, 30.0]), a = 5.0)
414

15+
julia> ca[[:c, :a]] == ca[(:c, :a)]
16+
true
17+
18+
julia> @view ca[(:c, :a)]
19+
ComponentVector{Float64,SubArray...}(c = (a = 2.0, b = [6.0, 30.0]), a = 5.0)
20+
```
521
### v0.11.0
622
- Calling `axes` on a `ComponentArray` returns a new `CombinedAxis` type!
723
- Doing things The Right Way™!

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ComponentArrays"
22
uuid = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66"
33
authors = ["Jonnie Diegelman <[email protected]>"]
4-
version = "0.11.17"
4+
version = "0.12.0"
55

66
[deps]
77
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"

docs/src/indexing_behavior.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,26 @@ julia> ca
3737
ComponentVector{Int64}(a = 0, b = [0, 1])
3838
```
3939

40+
## Indexing with multiple symbols
41+
It is often useful to create a new `ComponentArray` with only select fields of an old one. For this reason, `ComponentArray`s can be indexed with multiple symbolic names:
42+
```julia
43+
julia> ca = ComponentArray(a=5, b=[4, 1], c=(a=2, b=[6, 30.0]))
44+
ComponentVector{Float64}(a = 5.0, b = [4.0, 1.0], c = (a = 2.0, b = [6.0, 30.0]))
45+
46+
julia> ca[(:c, :a)]
47+
ComponentVector{Float64}(c = (a = 2.0, b = [6.0, 30.0]), a = 5.0)
48+
49+
julia> @view ca[(:c, :a)]
50+
ComponentVector{Float64,SubArray...}(c = (a = 2.0, b = [6.0, 30.0]), a = 5.0)
51+
```
52+
We see here that the new `ComponentArray` has the order of the `a` and `c` fields switched according to the order they were indexed by.
53+
54+
Multi-symbol indexing can be performed by passing either a `Tuple` or an `Array` of `Symbol`s.
55+
```julia
56+
julia> ca[[:c, :a]] == ca[(:c, :a)]
57+
true
58+
```
59+
4060
## Retaining component labels through index operations
4161
Sometimes you might want to index into a `ComponentArray` without dropping the component name. Let's look at a new example with a more deeply nested structure:
4262
```julia

src/ComponentArrays.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ using ArrayInterface
66
using LinearAlgebra
77
using Requires
88

9-
const FlatIdx = Union{Int, CartesianIndex, AbstractArray}
9+
const FlatIdx = Union{Integer, CartesianIndex, AbstractArray{<:Integer}}
1010
const FlatOrColonIdx = Union{FlatIdx, Colon}
1111

1212

src/axis.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,23 @@ reindex(ax::ViewAxis, offset) = ViewAxis(viewindex(ax) .+ offset, indexmap(ax))
158158
ComponentIndex(getproperty(IdxMap, s))
159159
@inline Base.getindex(::AbstractAxis{IdxMap}, ::Val{s}) where {IdxMap, s} =
160160
ComponentIndex(getproperty(IdxMap, s))
161+
function Base.getindex(ax::AbstractAxis, syms::Union{NTuple{N,Symbol}, <:AbstractArray{Symbol}}) where {N}
162+
@assert allunique(syms) "Indexing symbols must all be unique. Got $syms"
163+
c_inds = getindex.((ax,), syms)
164+
inds = map(x->x.idx, c_inds)
165+
axs = map(x->x.ax, c_inds)
166+
last_index = 0
167+
new_axs = map(inds, axs) do i, ax
168+
first_index = last_index + 1
169+
last_index = last_index + length(i)
170+
_maybe_view_axis(first_index:last_index, ax)
171+
end
172+
new_ax = Axis(NamedTuple(syms .=> new_axs))
173+
return ComponentIndex(reduce(vcat, inds), new_ax)
174+
end
175+
176+
_maybe_view_axis(inds, ax::Axis) = ViewAxis(inds, ax)
177+
_maybe_view_axis(inds, ::NullAxis) = inds[1]
161178

162179
struct CombinedAxis{C,A} <: AbstractUnitRange{Int}
163180
component_axis::C

src/componentindex.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ ComponentIndex(vax::ViewAxis{Inds,IdxMap,Ax}) where {Inds,IdxMap,Ax} = Component
99
const FlatComponentIndex{Idx} = ComponentIndex{Idx, FlatAxis}
1010
const NullComponentIndex{Idx} = ComponentIndex{Idx, NullAxis}
1111

12+
Base.:(==)(ci1::ComponentIndex, ci2::ComponentIndex) = ci1.idx == ci2.idx && ci1.ax == ci2.ax
13+
1214

1315
"""
1416
KeepIndex(idx)

src/utils.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
toval(x::Val) = x
66
toval(x) = Val(x)
77
toval(x::String) = Val(Symbol(x))
8+
toval(x::AbstractArray{Symbol}) = Val((x...,))
89

910
# Get value from Val type
1011
getval(::Val{x}) where x = x

test/runtests.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ end
170170
@test ca[:b] == ca["b"] == ca.b
171171
@test ca[:c] == ca["c"] == ca.c
172172

173+
@test ca[(:a, :c)].c == ca[(:c, :a)].c == ca.c
174+
@test ca[(:a, :c)].a isa Number
175+
@test ca[[:a, :c]] == ca[(:a, :c)]
176+
@test_throws AssertionError ca[(:a, :a)]
177+
173178
@test cmat[:a, :a] == cmat["a", "a"] == 10000.0
174179
@test cmat[:a, :b] == cmat["a", "b"] == [400, 130]
175180
@test all(cmat[:c, :c] .== ComponentArray(a[4:10] .* a[4:10]', Axis(ax_c), Axis(ax_c)))
@@ -298,6 +303,7 @@ end
298303
@test ax[:a] == ax[1] == ComponentArrays.ComponentIndex(1, ComponentArrays.NullAxis())
299304
@test ax[:c] == ax[3:4] == ComponentArrays.ComponentIndex(3:4, FlatAxis())
300305
@test ax[:d] == ComponentArrays.ComponentIndex(5:8, Axis(a = 1:3, b = 4))
306+
@test ax[(:a, :c)] == ax[[:a, :c]] == ComponentArrays.ComponentIndex([1, 3, 4], Axis(a = 1, c = 2:3))
301307
end
302308

303309
@testset "KeepIndex" begin

0 commit comments

Comments
 (0)