广播运算符. 适用于任何函数,包括关系运算符,也适用于赋值。因此,一个直观的单行是:
x[x .> 5] .= 5
这部分x .> 5 在x 上广播> 5,产生一个指示大于5 的元素的布尔向量。这部分.= 5 在x[x .> 5] 指示的所有元素上广播5 的分配。
但是,受以下 Benoit 非常酷的答案中 显着 加速的启发(请检查一下),我决定还添加一个带有速度测试的优化变体。上述方法虽然看起来非常直观,但并不是最优的,因为它为索引分配了一个临时的布尔数组。避免临时分配的(更多)最佳方法是:
function f_cond!(x::Vector{Int}, f::Function, val::Int)
@inbounds for n in eachindex(x)
f(x[n]) && (x[n] = val)
end
return x
end
因此,使用此函数,我们将编写f_cond!(x, a->a>5, 5),它将5 分配给条件(匿名)函数a->a>5 计算结果为true 的任何元素。显然,这个解决方案不是一个简洁的单行,但请查看以下速度测试:
julia> using BenchmarkTools
julia> x1 = rand(1:10, 100);
julia> x2 = copy(x1);
julia> @btime $x1[$x1 .> 5] .= 5;
327.862 ns (8 allocations: 336 bytes)
julia> @btime f_cond!($x2, a->a>5, 5);
15.067 ns (0 allocations: 0 bytes)
这速度快得离谱。此外,您可以将Int 替换为T<:Any。考虑到加速,人们可能想知道Base 中是否有一个已经这样做的函数。单行是:
map!(a->a>5 ? 5 : a, x, x)
虽然这比第一种方法显着加快了速度,但远低于第二种方法。
顺便说一句,我觉得这肯定是另一个 StackOverflow 问题的重复,但 5 分钟的搜索没有发现任何问题。