【问题标题】:Multidimensional Array Comprehension in JuliaJulia 中的多维数组理解
【发布时间】:2013-10-13 17:00:09
【问题描述】:

我在和 Julia 打交道,似乎无法让多维数组解析起作用。我正在为 OSX 使用 0.20-pre 的每晚版本;可以想象,这可能是构建中的错误。但是,我怀疑这是用户的错误。

假设我想以类似的方式结束:

5x2 Array
1 6
2 7
3 8
4 9
5 10

我不想只打电话给reshape。据我所知,应该生成一个多维数组,例如:[(x, y) for x in 1:5, y in 6:10]。但这会生成一个 5x5 元组数组:

julia> [(x, y) for x in 1:5, y in 6:10]
5x5 Array{(Int64,Int64),2}:
 (1,6)  (1,7)  (1,8)  (1,9)  (1,10)
 (2,6)  (2,7)  (2,8)  (2,9)  (2,10)
 (3,6)  (3,7)  (3,8)  (3,9)  (3,10)
 (4,6)  (4,7)  (4,8)  (4,9)  (4,10)
 (5,6)  (5,7)  (5,8)  (5,9)  (5,10)

或者,也许我想为每个值生成一组值和一个布尔代码:

5x2 Array
1 false
2 false
3 false
4 false
5 false

再一次,我似乎只能用{(x, y) for x in 1:5, y=false} 创建一个元组数组。如果我删除x, y 周围的括号,我会得到ERROR: syntax: missing separator in array expression。如果我将x, y 包裹在某些东西中,我总是会得到那种输出——ArrayArray{Any}Tuple

我的猜测:有些东西我只是不明白。有人愿意帮我理解什么吗?

【问题讨论】:

    标签: julia


    【解决方案1】:

    我认为理解不适合您正在尝试做的事情。原因可以在Array Comprehension section of the Julia Manual找到:

    A = [ F(x,y,...) for x=rx, y=ry, ... ]
    

    这种形式的含义是 F(x,y,...) 是用变量 x、y 等计算的,它们取给定值列表中的每个值。值可以指定为任何可迭代对象,但通常是范围,如 1:n 或 2:(n-1),或明确的值数组,如 [1.2, 3.4, 5.7]。 结果是一个 N-d 密集数组,其维度是变量范围 rx、ry 等的维度的串联,并且每个 F(x,y,...) 评估返回一个标量。

    这里需要注意的是,如果将其中一个变量设置为 >1 维数组,它似乎首先会变平;所以“结果是......一个数组,其维度是变量范围 rx、ry 等的维度的串联”并不是很准确,因为如果 rx 是 2x2 并且 ry 是 3,那么你不会得到 2x2x3 结果,而是 4x3。但是根据上述情况,您得到的结果应该是有意义的:您正在返回一个元组,所以这就是 Array 单元格中的内容。返回的元组不会自动扩展为 Array 的行。

    如果你想从理解中得到一个 5x2 数组,你需要确保 x 的长度为 5,y 的长度为 2。然后每个单元格将包含函数的结果使用来自xy 的每个可能的元素对作为参数进行评估。问题是示例数组的单元格中的值实际上并不需要评估两个参数的函数。相反,您要做的只是将两个预定的列粘在一起形成一个二维数组。为此,请使用 hcat 或文字:

    • hcat(1:5, 6:10)
    • [ 1:5 5:10 ]
    • hcat(1:5, falses(5))
    • [ 1:5 falses(5) ]

    如果您想创建一个 2D 数组,其中第 2 列包含对第 1 列求值的函数的结果,您可以使用如下推导式来执行此操作:

    f(x) = x + 5
    [ y ? f(x) : x for x=1:5, y=(false,true) ]
    

    但这有点令人困惑,对我来说这样做似乎更直观

    x = 1:5
    hcat( x, map(f,x) )
    

    【讨论】:

    • 好的,下面这个加上@ivarne 的评论是有道理的。我来自 Python,但我显然没有在第一次通过时摸索手册。感谢您帮助澄清!我剩下的问题是:我找到了[ 1:5 falses(5) ],这是完美的除了,它将false 编码为0。Julia 文档指定Julia 不使用0/1 进行布尔编码。 0 == false 返回 true,但 if(0) 抛出类型错误。有没有办法hcat 带有返回布尔值而不是 Int 编码的布尔值的数字?
    • @Gastove 是的,这里发生的是falses 正在从promotedInt64。我已经尝试了一段时间,但我想不出一种方法来优雅地获得带有错误的 5x2 数组。您可以尝试键入数组,但我无法让它工作:Any[ 1:5 falses(5) ] 将返回一个 1x2(范围或 falses 数组均未扩展),Union(Number,Bool)[ 1:5 falses(5) ] 引发错误。这是有效的代码:a = Array(Union(Number,Bool),5,2); a[:,1] = 1:5; a[:,2] = falses(5)
    • 嗯,非常感谢您的帮助,无论是哪种方式。我有一种预感,制作一个适当尺寸的单元格数组,然后填充它会起作用,但我还没有把它弄乱到足以让它继续下去。仍然习惯朱利安思维。
    【解决方案2】:

    我认为你只是在阅读列表理解错误

    julia> [x+5y for  x in 1:5, y in 0:1]
    5x2 Array{Int64,2}:
     1   6
     2   7
     3   8
     4   9
     5  10
    

    当您在多个维度中使用它们时,您会得到两个变量,并且需要一个基于坐标的单元格值的函数

    对于您的第二个问题,我认为您应该重新考虑您的要求。 Julia 使用类型化数组来提高性能,并且可以在不同的列中存储不同的类型。要获得一个无类型数组,您可以使用 {} 而不是 [],但我认为更好的解决方案是拥有一个元组数组 (Int, Bool),或者更好的是只使用两个数组(一个用于 int,一个用于 bool )。

    julia> [(i,false) for i in 1:5]
    5-element Array{(Int64,Bool),1}:
     (1,false)
     (2,false)
     (3,false)
     (4,false)
     (5,false)
    

    【讨论】:

    • 是的,我明白我所做的不符合 Julia 的优化方式——但是,目前我需要的是一个可变数组,所以我可以翻转 @987654323 @ 到 true 稍后;遗憾的是,使用元组不允许这样做。不过,使用两个单独的数组实际上可能效果很好!我会看看——感谢您的建议/时间!
    【解决方案3】:

    我有点喜欢@fawr 在保持可变性的同时为数据类型的效率提供的答案,但这很快就能满足您的要求(根据 Shawn 的回答):

    hcat(1:5,6:10)
    hcat({i for i=1:5},falses(5))
    

    第二部分的元胞数组理解强制数据类型为 Any 而不是 IntXX

    这也有效:

    hcat(1:5,{i for i in falses(5)})
    

    除了推导式之外,我还没有找到另一种将数组显式转换为 Any 类型的方法。

    【讨论】:

      【解决方案4】:

      您的直觉是写[(x, y) for x in 1:5, y in 6:10],但您需要将范围包装在zip 中,如下所示:

      [i for i in zip(1:5, 6:10)]
      

      这为您提供了非常接近您需要的东西,即:

      5-element Array{(Int64,Int64),1}:
      (1,6) 
      (2,7) 
      (3,8) 
      (4,9) 
      (5,10)
      

      要准确获得所需的内容,您需要:

      hcat([[i...] for i in zip(1:5, 6:10)]...)'
      

      这给了你:

      5x2 Array{Int64,2}:
      1   6
      2   7
      3   8
      4   9
      5  10
      

      【讨论】:

        【解决方案5】:

        这是另一种(尽管很复杂)方式:

        x1 = 1
        x2 = 5
        
        y1 = 6
        y2 = 10
        
        x = [x for x in x1:x2, y in y1:y2]
        y = [y for x in x1:x2, y in y1:y2]
        
        xy = cat(2,x[:],y[:])
        

        【讨论】:

          【解决方案6】:

          正如@ivarne 指出的那样

          [{x,false} for  x in 1:5]
          

          会起作用并给你一些可变的东西

          【讨论】:

            【解决方案7】:

            我找到了一种通过vcatsplat 运算符生成数值多维数组的方法:

            R = [ [x y] for x in 1:3, y in 4:6 ] # make the list of rows
            A = vcat(R...) # make n-dim. array from the row list
            

            然后R 将是3x3 Array{Array{Int64,2},2}A9x2 Array{Int64,2},如您所愿。

            对于第二种情况(一组值和一个布尔代码),可以执行类似的操作

            R = [[x y > 5] for x in 1:3, y in 4:6] # condition is y > 5
            A = vcat(R...)
            

            其中A 将是9x2 Array{Int64,2},其中true/false1/0 表示。

            我已经在 J​​ulia 0.4.7 中测试过。

            【讨论】:

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