# `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)
``````