Julia:创建自定义类型的空/初始化多维数组

5

我正在创建一种自己的类型,名为KeyVal,如下所定义:

type KeyVal
    first::Int
    second::Float64
end

我正在尝试创建一个元素类型为KeyVal的空矩阵或初始化为零。 通常我会使用其他类型:

myMat = zeros(KeyVal, (10,3))

但是这样不起作用,因为这个复合类型没有定义zeros。所以我尝试按照以下方式定义自己的zeros函数:
import Base.zeros

function zeros(KeyVal,dims)
    if length(dims) > 1
        n=dims[1]
        m=dims[2]
        temp = repeat([KeyVal(0,0.0)], outer=m*n)
        temp = reshape(temp, (n,m))
        return temp
    elseif length(dims) == 1
        n=dims[1]
        temp= repeat([KeyVal(0,0.0)], outer=n)
        temp = reshape(temp, (n))
        return temp
    end
end

这将添加到先前定义的其他zeros方法列表中。 但是使用它会生成错误:

myMat = zeros(KeyVal, (N,M))

MethodError: no method matching zero(::Type{KeyVal})
Closest candidates are:
    .....

我想知道是否可以通过某种方式解决这个问题,或者在类型构造函数中发出一个信号,以便涉及类型KeyVal的任何数据结构都会初始化为(first=0,second=0.0)。

之前我试过将矩阵定义为:

myMat2 = Array{KeyVal,(N,M)}

这将创建矩阵,但是所有元素都是#undef,在这种情况下我无法访问myMat2的任何元素:

myMat2[1,1]
UndefRefError: access to undefined reference
1个回答

4
您可以使用以下代码创建一个未初始化的任意类型 T 和维度 N 的数组:
Array{T, N}(undef, dims...)

在一维和二维数组的特殊情况下,您可以使用别名VectorMatrix,例如:

julia> m = Matrix{KeyVal}(undef, 2,2)
2×2 Array{KeyVal,2}:
 #undef  #undef
 #undef  #undef

您可以像平常一样设置元素,例如:
m[1,2] = KeyVal(1,2)

如果你的类型实现zero方法有意义,那么你可以定义它。
Base.zero(::Type{KeyVal}) = KeyVal(0,0)

并且 zeros 将会正确地工作。

julia> zeros(KeyVal, (2,2))
2×2 Array{KeyVal,2}:
 KeyVal(0,0.0)  KeyVal(0,0.0)
 KeyVal(0,0.0)  KeyVal(0,0.0)

警告:

zeros使用fill!来填充数组,该函数会用同一个实例的副本来填充整个数组。相反,应该使用下面的推导式或者一个不包含引用的不可变类型(isbits为真)。后一种方法更快,因为数组可以作为一个连续块的内存存储。在这种情况下,您也可以直接使用fill(KeyVal(0,0), dims..)而不是定义zero函数。在0.6版本中,新的struct关键字默认创建不可变类型。

编辑:

另一个可能性是使用一个推导式。

julia> m = [KeyVal() for i=1:3, j=1:2]
3×2 Array{KeyVal,2}:
 KeyVal(0,0.0)  KeyVal(0,0.0)
 KeyVal(0,0.0)  KeyVal(0,0.0)
 KeyVal(0,0.0)  KeyVal(0,0.0)

为了方便起见,我先前定义了外部构造函数

KeyVal() = KeyVal(0,0)

谢谢,有趣的是仅运行m[1,2]会导致错误,但是 = KeyVal(1,2)完全正常,但零扩展是最方便的解决方案。 - A.Yazdiha
1
错误阻止了对未定义引用的访问。请注意,对于“不可变”类型,不会抛出错误,而是将未初始化的矩阵填充为随机值。 - tim
然而,使用zeros()方法存在一个问题,因为只有一个实例,如果我想要更改m[i,j]的值,这也会改变其他地方的所有实例。 - A.Yazdiha
1
@A.Yazdiha 你是对的!zeros是使用fill!实现的,它用相同的实例填充数组。使用我的编辑中的推导式或不可变类型代替。后一种方法可能也具有更高的性能。 - tim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接