Julia count()函数的结构数组

问题描述 投票:4回答:2

我如何使用count()而不是for循环来获取以下Julia代码以工作(计算房屋中的成年人)?

mutable struct Person
    age
end
mutable struct House
    people::Array{Person}
end
function Adults(h::House)
    numAdults = 0
    for n in 1:length(h.people)
        if h.people[n].age > 18; numAdults = numAdults + 1; end
    end
    numAdults
# count(h.people.age > 18, h.people) is there some variant of this that works?    
end
p1 = Person(10)
p2 = Person(40)
h1 = House([p1, p2])
Adults(h1)
arrays julia counting
2个回答
2
投票

Julia中的for循环没有错!它通常与等效的“矢量化”版本一样快(如果不是更快的话)。就是说,有时使用高阶函数可以使您的代码更简洁,这很好。在这种情况下,您希望将anonymous function传递给count,以计算单个元素所需的比较。

julia> f = (x->x.age > 18)
#7 (generic function with 1 method)

julia> f(p1)
false

julia> f(p2)
true

您可以将其传递给Julia的任何高阶函数,并在执行操作时将其应用于每个元素:

julia> count(x->x.age > 18, h1.people)
1

julia> map(x->x.age > 18, h1.people)
2-element Array{Bool,1}:
 0
 1

julia> filter(x->x.age > 18, h1.people)
1-element Array{Person,1}:
 Person(40)

(顺便说一句,您可能希望确保struct fields are concretely typed达到最佳性能;这将同样影响for循环和count的性能。]


0
投票

这只是匿名函数的语法糖,但是您可以使用do block

function adults(h::House)
    return count(h.people) do person
        person.age > 18
    end  
end

更接近您在评论中写的是

adults(h::House) = count(getproperty.(h.people, :age) .> 18)

但是这有点不易读(财产广播没有糖,并且构造了不必要的中间数组。

有一种使用生成器的中间形式,不会增加过多的内存:

adults(h::House) = count(person.age > 18 for person in h.people)

这可能是我想要的。

最后,可以说,在所有版本中,您编写的版本并没有那么少习惯,尽管我会这样写,但它在微型基准测试中很有可能是所有版本中最快的:

function adults(h::House)
    count = 0
    for i in eachindex(h.people)
        count += Int(h.people[i].age > 18)
    end
    return count   
end

最后:此功能是自然的地图缩减任务,如果您使用纯功能性方法(例如使用换能器或@distributed for,则可以打开更多的可能性。]

© www.soinside.com 2019 - 2024. All rights reserved.