在 Julia 中过滤字典

ima*_*tha 5 julia

我想使用函数过滤字典filter(),但我遇到了麻烦。我希望完成的是,返回值的某些条件的密钥。但是我遇到了方法错误

using Agents: AbstractAgent

# Define types
mutable struct Casualty <: AbstractAgent
    id::Int 
    ts::Int
    rescued::Bool 

    function Casualty(id,ts; rescued = false)
        new(id,ts,rescued)
    end
end

mutable struct Rescuer <: AbstractAgent
    id::Int
    actions::Int
    dist::Float64

    function Rescuer(id; action = rand(1:3) , dist = rand(1)[1])
        new(id,action,dist)
    end
end

cas1 = Casualty(1,2)
cas2 = Casualty(2,3)
resc1 = Rescuer(3)

agents = Dict(1=> cas1, 2 => cas2, 3 => resc1)
Run Code Online (Sandbox Code Playgroud)

现在要过滤

filter((k,v) -> v isa Casualty, agents)

# ERROR: MethodError: no method matching (::var"#22#23")(::Pair{Int64, AbstractAgent})

# what I truly wish to achieve is return the key for some condition of the value

filter((k,v) -> k ? v isa Casualty : "pass", agents)
# ofcourse I am not sure how to "pass" using this format
Run Code Online (Sandbox Code Playgroud)

知道我如何才能实现这一目标。谢谢

Bog*_*ski 7

对于字典filter获取键值对,也可以这样做(解构Pair):

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

julia> filter(((k,v),) -> k == 1 || v == "c", dict)
Dict{Int64, String} with 2 entries:
  3 => "c"
  1 => "a"
Run Code Online (Sandbox Code Playgroud)

或者例如(作为Pair一个整体):

julia> filter(p -> first(p) == 1 || last(p) == "c", dict)
Dict{Int64, String} with 2 entries:
  3 => "c"
  1 => "a"

julia> filter(p -> p[1] == 1 || p[2] == "c", dict)
Dict{Int64, String} with 2 entries:
  3 => "c"
  1 => "a"
Run Code Online (Sandbox Code Playgroud)

编辑

解释为什么需要额外的括号:

julia> f = (x, y) -> (x, y)
#1 (generic function with 1 method)

julia> g = ((x, y),) -> (x, y)
#3 (generic function with 1 method)

julia> methods(f)
# 1 method for anonymous function "#1":
[1] (::var"#1#2")(x, y) in Main at REPL[1]:1

julia> methods(g)
# 1 method for anonymous function "#3":
[1] (::var"#3#4")(::Any) in Main at REPL[2]:1

julia> f(1, 2)
(1, 2)

julia> f((1, 2))
ERROR: MethodError: no method matching (::var"#1#2")(::Tuple{Int64, Int64})
Closest candidates are:
  (::var"#1#2")(::Any, ::Any) at REPL[1]:1

julia> g(1, 2)
ERROR: MethodError: no method matching (::var"#3#4")(::Int64, ::Int64)
Closest candidates are:
  (::var"#3#4")(::Any) at REPL[2]:1

julia> g((1, 2))
(1, 2)
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,f需要 2 个位置参数,而g需要 1 个被解构的位置参数(即假设传递给的参数g是可迭代的并且至少有 2 个元素)。另请参阅https://docs.julialang.org/en/v1/manual/functions/#Argument-destructuring

现在是棘手的部分:

julia> h1((x, y)) = (x, y)
h1 (generic function with 1 method)

julia> methods(h1)
# 1 method for generic function "h1":
[1] h1(::Any) in Main at REPL[1]:1

julia> h2 = ((x, y)) -> (x, y)
#1 (generic function with 1 method)

julia> methods(h2)
# 1 method for anonymous function "#1":
[1] (::var"#1#2")(x, y) in Main at REPL[3]:1
Run Code Online (Sandbox Code Playgroud)

在此示例中h1是一个命名函数。在这种情况下,只需将参数括在额外的括号中即可获得解构行为。对于匿名函数,由于 Julia 解析器的工作方式,,需要额外的 - 如果省略它,则额外的括号将被忽略。

现在让我们检查filter文档字符串:

过滤器(f,d::AbstractDict)

返回 d 的副本,删除 f 为 false 的元素。函数 f 传递 key=>value 对。

正如您可以从此文档字符串中看到的,f传递了一个参数,即Pair. 这就是为什么您需要使用解构或定义单个参数函数并在函数内提取其元素。

  • 第一个版本稍微好一点的语法是 `filter((k, v)::Pair -&gt; k == 1 || v == "c",, dict) `(归功于 [Fredrik Ekre](https:// github.com/JuliaLang/julia/issues/44392#issuecomment-1055519519))。 (3认同)