【问题标题】:Julia conditional assignment based on | (or) in multidimensional arrayJulia 条件赋值基于 | (或)在多维数组中
【发布时间】:2021-04-18 17:02:24
【问题描述】:

我有一个 3D 数组,并且基于使用或运算符“|”的一个“行”中的值,我想替换不同行中的值。我试图建立一个 mwe,这里是:

# create new array
Pop = fill(Int8(3), 1, 3, 4)

# change values in one row of array
Pop[:,:,2] = [5,6,7]

# change values in second row of array
Pop[:,:,4] = [9,10,11]


#  attempt conditional substitution, if element-wise value of Pop[:,:,2] equals either 6 or 7,  then substitute the corresponding element wise (across row in dimension 3) for 8
Pop[:,:,2] == 6|7 Pop[:,:,3] .= 8

# to produce this end result
Pop[:,:,3] = [3,8,8]

Pop

我在替换的语法中遗漏了一些东西。谢谢。 J

【问题讨论】:

    标签: arrays julia conditional-operator


    【解决方案1】:

    这可行,但需要一个临时变量。

    julia> temp = Pop[:,:,3]
    1×3 Array{Int8,2}:
     3  3  3
    
    julia> temp[(Pop[:,:,2] .== 6) .| (Pop[:,:,2] .== 7)] .= 8
    2-element view(::Array{Int8,1}, [2, 3]) with eltype Int8:
     8
     8
    
    julia> Pop[:,:,3] = temp
    1×3 Array{Int8,2}:
     3  8  8
    

    【讨论】:

    • 谢谢@Nathan Boyer。这行得通。我设法添加了更多条件并使其正常工作,将发布一个有效的解决方案,但如果有更优雅或更简单的解决方案,请告诉我。
    【解决方案2】:

    我认为将阶段分开更清楚:

    julia> Pop = fill(Int8(3), 1, 3, 4);
    
    julia> Pop[:,:,2] .= [5 6 7];
    
    julia> ind = findall(x -> x==6 || x==7, Pop[:,:,2])
    2-element Vector{CartesianIndex{2}}:
     CartesianIndex(1, 2)
     CartesianIndex(1, 3)
    
    julia> Pop[ind, 3] .= 8;
    
    julia> Pop[:, :, 3]
    1×3 Matrix{Int8}:
     3  8  8
    

    你也可以写ind == findall(in((6,7)), @view Pop[:,:,2])。您可以写 ind_bool = (Pop[:,:,2] .== 6) .| (Pop[:,:,2] .== 7),但我不确定 Pop[ind_bool, 3] .= 8 是否适用于所有版本的 Julia。

    另一种方法是编写一个显式循环。我们可以在 for i in axes(Pop,1), j in axes(Pop,2) 上单独循环,但我们也可以再次使用这些多维 CartesianIndex 的东西:

    julia> Pop = fill(Int8(3), 1, 3, 4);
    
    julia> Pop[:,:,2] .= [5 6 7];
    
    julia> for i in CartesianIndices(@view Pop[:,:,2])
             x = Pop[i,2]
             if x==6 | x==7
               Pop[i,3] = 8
             end
           end
    
    julia> Pop[:, :, 3]
    1×3 Matrix{Int8}:
     3  3  8
    

    【讨论】:

    • 感谢@mcabbott,非常有用。我来自多年的 R,有没有办法通过将正在搜索的 6 和 7 分组来减少/缩短,比如 "(6 |7)" ?欣赏的问题是相当琐碎的,但在网上还很少有例子,所以会继续问。在 Julia 中,循环速度较慢,就像在 R 中一样?谢谢一堆。
    • 请注意,6 |7 已经有含义,它是按位或,并且没有特殊评估,因此首先发生。我认为x in (6,7) 是您想要的分组,它构造一个元组(它是免费的),然后检查 x 是否是成员,即等于某个元素。循环通常并不慢,广播本身就是循环。在这里,循环还避免为indind_bool 分配存储空间。 (可能会有边界检查和迭代顺序等警告。我写的是全局范围,但如果你关心速度,应该在函数中。)
    • 再次感谢,我可以再推你一份吗?如果我有两个(或更多)条件要满足,基于两个“行”,例如“如果 Pop[:,:,2] 的任何列中的值 == 6 或 7 ...并且 ... Pop[:,:,4] 的同一列中的值 >= 10,然后将 8 的值替换为 Pop[:,:,3] ?我已经尝试了几件事,但到目前为止都不起作用.谢谢。
    • 你能在循环中提取x = Pop[i,2]; y = Pop[i,4]然后if x in (6,7) && y >= 10吗?
    • 我是否还需要 "@view Pop[:,:,4]" 才能将 "y = Pop[i,4]" 放入循环中?
    【解决方案3】:

    感谢@mcabbott 和@Nathan Boyer 的帮助,我找到了一个可行的解决方案,甚至设法添加了更多条件,而且它似乎可以工作。我将发布 mwe 解决方案。

    # create new array
    Pop = fill(Int8(3), 1, 3, 4)
    # change some values
    Pop[:,:,2] = [5,6,7]
    Pop[:,:,4] = [9,10,9]
    # what does it look like
    Pop
    
    # code to check condition values
    
    # create temp array to be altered if conditions met
    temp = Pop[:,:,3]
    # see which indexes meet conditions, in this case
    # array "Pop[:,:,2]" contains either 6 or 7 ... and ...
    # array "Pop[:,:,4]" contains values >= 10
    temp[(Pop[:,:,2] .== 6) .|
         (Pop[:,:,2] .== 7) .&
         (Pop[:,:,4] .>= 10)] .= 8
    # make changes to original array based on temp
    Pop[:,:,3] = temp
    # check if it did the job correctly
    Pop
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多