Julia 向量数组的条件赋值语法

Julia 向量数组的条件赋值语法,julia,Julia,我是Julia的新手,更多来自Matlab和Python 我无法理解向量数组条件赋值的Julia语法。在我看来,它似乎与数字数组的条件赋值不一致 对于数字数组,我可以执行以下操作: a = [1,2,3] b = [0,1,1] a[b.>0] .= 5 这将用新值5替换a的两个元素 我的实际工作示例是使用数组{Int64,1}类型元素的数组: a = [[1,0,0], [0,1,0], [0,0,1]] b = [0,1,1] a[b.>0] .= Int64[0,0,5]

我是Julia的新手,更多来自Matlab和Python

我无法理解向量数组条件赋值的Julia语法。在我看来,它似乎与数字数组的条件赋值不一致

对于数字数组,我可以执行以下操作:

a = [1,2,3]
b = [0,1,1]
a[b.>0] .= 5
这将用新值5替换a的两个元素

我的实际工作示例是使用数组{Int64,1}类型元素的数组:

a = [[1,0,0], [0,1,0], [0,0,1]]
b = [0,1,1]
a[b.>0] .= Int64[0,0,5]
这不起作用,输出为: 错误:维度不匹配(“无法广播数组以匹配目标”)

但是,这条线可以工作:

a[b.>0] .= [Int64[0,0,5]]
我无法理解这一点,因为在后一种情况下,元素赋值(.=)对我来说就更没有意义了,因为左侧和右侧的两个数组具有不同的大小

有人能解释一下吗


提前感谢。

逻辑索引仅选择条件为真的元素。对于
a[b.>0]
,选择两个元素:

julia> a[b.>0]
2-element Array{Int64,1}:
 2
 3
您正试图将三个元素分配到这两个位置:

julia> a[b.>0] .= [10,20,30]
ERROR: DimensionMismatch("array could not be broadcast to match destination")
您还可以使用相同的条件逻辑将要分配的值数组子集,以选择应分配的两个元素:

julia> a[b.>0] .= [10,20,30][b.>0]
2-element view(::Array{Int64,1}, [2, 3]) with eltype Int64:
 20
 30

julia> a
3-element Array{Int64,1}:
  1
 20
 30
语法
a[b.>0].=[Int64[0,0,5]]
只有在
a
Any
数组时才起作用,它的意思完全不同。它将值数组本身广播到所有选定的位置,也就是说,它将整个数组作为重复元素放入
a

julia> a = Any[1,2,3]
3-element Array{Any,1}:
 1
 2
 3

julia> a[b.>0] .= [Int64[0,0,5]]
2-element view(::Array{Any,1}, [2, 3]) with eltype Any:
 [0, 0, 5]
 [0, 0, 5]

julia> a
3-element Array{Any,1}:
 1
  [0, 0, 5]
  [0, 0, 5]
行动:

x .= y
尝试迭代
x
y
并执行赋值。一个简单的例子是:

julia> x = [1,2,3,4]
4-element Array{Int64,1}:
 1
 2
 3
 4

julia> y = [12,14]
2-element Array{Int64,1}:
 12
 14

julia> x[[2,4]] .= y
2-element view(::Array{Int64,1}, [2, 4]) with eltype Int64:
 12
 14

julia> x
4-element Array{Int64,1}:
  1
 12
  3
 14
我们看到左侧和右侧有2个元素,因此可以执行就地分配

然后Julia有一个特殊规则,如果右侧的容器长度为1,则可以将其展开以匹配左侧的大小(这也适用于比1更高的维度,但让我们关注一个简单的情况)

例如,您有:

julia> x = [1,2,3,4]
4-element Array{Int64,1}:
 1
 2
 3
 4

julia> x[[2,4]] .= 11
2-element view(::Array{Int64,1}, [2, 4]) with eltype Int64:
 11
 11

julia> x
4-element Array{Int64,1}:
  1
 11
  3
 11

julia> length(11)
1

julia> x[[2,4]] .= [11]
2-element view(::Array{Int64,1}, [2, 4]) with eltype Int64:
 11
 11

julia> x
4-element Array{Int64,1}:
  1
 11
  3
 11

julia> length([1])
1
这里需要注意的一个关键点是,
[1]
1
在这种情况下的行为完全相同,因为数字被视为一个在广播中包含该数字的单元素容器

现在来看您的示例:

a = [[1,0,0], [0,1,0], [0,0,1]]
b = [0,1,1]
a[b.>0] .= Int64[0,0,5]
失败的原因是:

julia> length(a[b.>0])
2

julia> length(Int64[0,0,5])
3
我们看到尺寸不匹配

但在以下方面:

a[b.>0] .= [Int64[0,0,5]]
你有:

julia> length([Int64[0,0,5]])
1
因此,长度为1的容器将被展开

但是,请注意,您很可能不想执行
a[b.>0]。=[Int64[0,0,5]
赋值,因为
a
将保存相同的数组
Int64[0,0,5]
。例如

julia> a = [[1,0,0], [0,1,0], [0,0,1]]
3-element Array{Array{Int64,1},1}:
 [1, 0, 0]
 [0, 1, 0]
 [0, 0, 1]

julia> b = [0,1,1]
3-element Array{Int64,1}:
 0
 1
 1

julia> a[b.>0] .= [Int64[0,0,5]]
2-element view(::Array{Array{Int64,1},1}, [2, 3]) with eltype Array{Int64,1}:
 [0, 0, 5]
 [0, 0, 5]

julia> a
3-element Array{Array{Int64,1},1}:
 [1, 0, 0]
 [0, 0, 5]
 [0, 0, 5]

julia> a[2][1] = 100
100

julia> a
3-element Array{Array{Int64,1},1}:
 [1, 0, 0]
 [100, 0, 5]
 [100, 0, 5]
在大多数情况下,这不是你想要的。一种更安全的方法是,例如,像这样为循环创建一个

julia> a = [[1,0,0], [0,1,0], [0,0,1]]
3-element Array{Array{Int64,1},1}:
 [1, 0, 0]
 [0, 1, 0]
 [0, 0, 1]

julia> b = [0,1,1]
3-element Array{Int64,1}:
 0
 1
 1

julia> for i in axes(b, 1)
           b[i] > 0 && (a[i] = Int64[0,0,5])
       end

julia> a
3-element Array{Array{Int64,1},1}:
 [1, 0, 0]
 [0, 0, 5]
 [0, 0, 5]

julia> a[2][1] = 100
100

julia> a
3-element Array{Array{Int64,1},1}:
 [1, 0, 0]
 [100, 0, 5]
 [0, 0, 5]

你可以看到,
a
的每个条目都是一个不同的对象。

这是一个非常好的答案(我同时写了我的,然后注意到了你的:)。我有一个小注释
a
不必有
任何类型,它的类型允许
向量{Int64}
元素就足够了。是的,非常正确。我过度简化了那里的文本,
Any
数组最有可能同时包含
Int
Vector{Int}
,因为这是它们唯一常见的超类型,但是
联合
当然也可以做到这一点。