如何在 Julia 1.0 中创建自定义迭代器?



我在Julia 1.0中有这个结构:

mutable struct Metadata
id::Int64
res_id::Int64
end

这样我就可以创建一个这样的数组,其中id总是递增 1,但res_id只是偶尔递增,如下所示:

data = [
Metadata(1, 1),
Metadata(2, 1),
Metadata(3, 1),
Metadata(4, 2),
Metadata(5, 2),
Metadata(6, 2),
...]

我想做的是能够迭代这个数组,但根据res_id获取块(所有数据都带有res_id1,然后是 2,依此类推(。所需的行为如下所示:

for res in iter_res(data)
println(res)
end
julia>
[Metadata(1, 1), Metadata(2, 1), Metadata(3, 1)]
[Metadata(4, 2), Metadata(5, 2), Metadata(6, 2)]

考虑到我还需要通常迭代数组以逐个元素获取,如何在 Julia 1.0 中执行此操作?

在 Julia 1+ 中,这应该通过实现Base.iterate(::YourType)来完成,以获取基于某些state的其他迭代的起始迭代和Base.iterate(::YourType, state)。这些方法应在完成后返回nothing,否则(result, state)元组。

使用 迭代您的类型

for i in x
# stuff
end

然后是写作的简写

it = iterate(x)
while it !== nothing
i, state = it
# stuff
it = iterate(x, state)
end

有关详细信息,请参阅手册。

我最终如何处理这个问题:

function iter(data::Vector{Metadata}; property::Symbol = :res_id)
#GET UNIQUE VALUES FOR THIS PROPERTY
up = Vector{Any}()
for s in data
getproperty(s, property) in up ? nothing : push!(up, getproperty(s, property))
end
#GROUP ELEMENTS BASED ON THE UNIQUE VALUES FOR THIS PROPERTY
f = Vector{Vector{Metadata}}()
idx::Int64 = 1
cmp::Any = up[idx]
push!(f, Vector{Metadata}())
for s in data
if getproperty(s, property) == cmp
push!(f[idx], s)
else
push!(f, Vector{Metadata}())
idx += 1
cmp = up[idx]
push!(f[idx], s)
end
end
return f
end

这允许我适应"跳过"的res_id(例如从 1 跳到 3 等(,甚至可以按res_id以外的其他未来特征(例如字符串或 Int64 以外的类型(对元数据对象进行分组。有效,尽管它可能不是很有效。

然后,您可以通过以下方式迭代 Vector{Metadata}:

for r in iter(rs)
println(res)
end

您可以像这样迭代过滤器生成器:

julia> mutable struct Metadata
id::Int64
res_id::Int64
end
julia> data = [
Metadata(1, 1),
Metadata(2, 1),
Metadata(3, 1),
Metadata(4, 2),
Metadata(5, 2),
Metadata(6, 2),
];
julia> for res in (filter(x -> x.res_id == i, data) for i in 1:2)
println(res)
end
Metadata[Metadata(1, 1), Metadata(2, 1), Metadata(3, 1)]
Metadata[Metadata(4, 2), Metadata(5, 2), Metadata(6, 2)]

从变量的名称来看,您似乎正在从某个计算过程中收集数据。通常,您将DataFrame用于此目的。

using DataFrames
data = DataFrame(id=[1,2,3,4,5,6],res_id=[1,1,1,2,2,2])
for group in groupby(data,:res_id)
println(group)
end

这会产生:

3×2 SubDataFrame{Array{Int64,1}}
│ Row │ id    │ res_id │
│     │ Int64 │ Int64  │
├─────┼───────┼────────┤
│ 1   │ 1     │ 1      │
│ 2   │ 2     │ 1      │
│ 3   │ 3     │ 1      │
3×2 SubDataFrame{Array{Int64,1}}
│ Row │ id    │ res_id │
│     │ Int64 │ Int64  │
├─────┼───────┼────────┤
│ 1   │ 4     │ 2      │
│ 2   │ 5     │ 2      │
│ 3   │ 6     │ 2      │

这也更便于进一步处理结果。

听起来你需要一个groupBy函数。这是一个供参考的实现,在 Haskell 中

groupBy                 :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _  []           =  []
groupBy eq (x:xs)       =  (x:ys) : groupBy eq zs
where (ys,zs) = span (eq x) xs

相关内容

  • 没有找到相关文章

最新更新