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

question
#1

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]).

0 Likes

#2

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

#4

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

0 Likes

#5

You could do

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

#6

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

0 Likes

#7

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
0 Likes

#8

this works

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

#9

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)
0 Likes

#10

Try

using LightQuery

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