Can you filter a Dict with pairs?


I can filter a Dict with first and last:

d = Dict("a" => 1, "b" => 2, "c" => 3)
filter(e -> first(e) == "a" || last(e) == 3, d)

But it would be really nice if I could destructure e into a key and a value:

filter((k, v) -> k == "a" || v == 3, d)  # doesn't seem to work
filter((k => v) -> k == "a" || v == 3, d) # nor does this.

Is something similar possible? Am I missing something, or are first and last the best options for filtering?


You can do this:

Looks a bit strange but it’s saying it’s a 1-arg function (hence the 1-tuple) whose argument should be destructured into k and v.


Thanks! It does look strange, but your explanation makes perfect sense!

1 Like

Oh, and filter(a) do (k, v) k == 'a" || v == 3 end also works, and is almost clearer.

You can also do a comprehension

Dict(k=>v for (k, v) in d if k == "a" || v == 3)
1 Like

Oh, thanks. I should have mentioned comprehensions. It’s really just a case of thinking that filter might convey the intent more clearly than a comprehension, and then finding that the syntax didn’t work as cleanly.

In fact, I’m trying to filter a Dict with a Set of keys. It would be really nice if an intersection worked:

d = Dict("a" => 1, "b" => 2, "c" => 3)
s = Set(["a", "c"])
d ∩ s # doesn't work - fair enough because it's trying to match the pairs in `d`

While that would indeed indeed nice notation for it, you can do that as well with a comprehension

# if all of the elements of s are definitely keys of d
Dict(k => d[k] for k in s)

# if not
Dict(k => d[k] for k in s if haskey(d, k))

# also possible with filter, but it's slower in general because it requires more inclusion checks. 
filter(e -> first(e) ∈ s, d)

another way to do it

You can also convert a two-argument function taking key and value to a single argument function using Base.splat

julia> kvfilter(f,d) = filter(Base.splat(f), d);

julia> kvfilter((k,v) -> v>1, Dict("a" => 1, "b" => 2, "c" => 3))
Dict{String, Int64} with 2 entries:
  "c" => 3
  "b" => 2