`filter` a `NamedTuple` based on one of the fields

How can I filter a NamedTuple based on a criteria applied to only one of its fields? For example

NT = (id=[1,2,3], val=[10,11,12])
NT_filtered = filter(x -> x.id == 2, NT)  ## doesn't work

and I’m hoping for the filter to return NT_filtered such that NT_filtered == (id=[2], val=[11]).

x.id == [1,2,3] and that is never going to equal 2. Are you trying select 2 if it is in x.id, or trying to select x.id if it contains 2 or something else?

also fyi, if you did not know

julia> NT
(id = [1, 2, 3], val = [10, 11, 12])

julia> NT.id
3-element Array{Int64,1}:
 1
 2
 3

julia> NT[:id]
3-element Array{Int64,1}:
 1
 2
 3

julia> NT[1]
3-element Array{Int64,1}:
 1
 2
 3
1 Like

My original attempt was NT_filtered = filter(x -> x.id .∈ [2], NT), but I’m missing something here, too

You could do

idx = findall(x -> x == 2, NT.id)
(id = NT.id[idx], val = NT.val[idx])
1 Like

Thanks! I’ll use this until I figure out a way to avoid reconstructing the tuple again

As a somewhat related follow up, why doesn’t the elementwise “in” operator work here?

x = collect(1:5)
x .∈ Set([2])   ## works
x .∈ Set([2,3]) ## doesn't work

this works

x .∈ Ref(Set([2,3])) # this works
2 Likes

Are you worried about performance? The impact of reconstructing the tuple should be negligible compared to filtering and creating new component vectors.

If you really want to avoid reconstructing the tuple, you could mutate the component vectors:

inds = findall(x -> x != 2, NT.id)
deleteat!(NT.id, inds)
deleteat!(NT.val, inds)

Try

using LightQuery

julia> @> NT |>
       rows |>
       when(_, @_ _.id == 2)