我在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_id
1,然后是 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