我如何使用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)
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
的性能。]
这只是匿名函数的语法糖,但是您可以使用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
,则可以打开更多的可能性。]