向量数组的条件赋值语法

时间:2019-08-05 15:09:57

标签: julia

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

我不了解用于向量数组的条件赋值的Julia语法。在我看来,这似乎与条件分配数字数组不一致。

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

a = [1,2,3]
b = [0,1,1]
a[b.>0] .= 5

这将a的两个元素替换为新值5。

我的实际工作示例是一个数组,其元素类型为Array {Int64,1}:

a = [[1,0,0], [0,1,0], [0,0,1]]
b = [0,1,1]
a[b.>0] .= Int64[0,0,5]

这不起作用,输出为: 错误:DimensionMismatch(“无法广播数组以匹配目标位置”)

但是,此行有效:

a[b.>0] .= [Int64[0,0,5]]

我无法理解这一点,因为在后一种情况下,按元素分配(。=)对我而言意义不大,因为左右两个数组的大小不同。

有人可以解释吗?

谢谢。

2 个答案:

答案 0 :(得分:3)

逻辑索引仅选择条件为真的那些元素。对于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]]仅在aAny数组的情况下才有效,这意味着完全不同。它将值数组本身广播到所有选定的位置-也就是说,它将整个数组作为重复元素放入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]

答案 1 :(得分:3)

操作:

x .= y

尝试遍历xy并执行分配。一个简单的例子是:

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在这种情况下的行为完全相同,因为在广播中,数字被视为拥有该数字的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]

,在大多数情况下,这不是您想要的。例如,像这样的for循环是一种更安全的方法:

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的每个条目都是一个不同的对象。