Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iterator 如何在Julia 1.0中创建自定义迭代器?_Iterator_Julia - Fatal编程技术网

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

Iterator 如何在Julia 1.0中创建自定义迭代器?,iterator,julia,Iterator,Julia,我在Julia 1.0中有这样的结构: mutable struct Metadata id::Int64 res_id::Int64 end 这样我就可以创建一个数组,其中id总是递增1,但是res\u id只是有时递增,如下所示: data = [ Metadata(1, 1), Metadata(2, 1), Metadata(3, 1), Metadata(4, 2), Metadata(5, 2), Metadata(6

我在Julia 1.0中有这样的结构:

mutable struct Metadata
    id::Int64
    res_id::Int64
end
这样我就可以创建一个数组,其中
id
总是递增1,但是
res\u id
只是有时递增,如下所示:

data = [
    Metadata(1, 1),
    Metadata(2, 1),
    Metadata(3, 1),
    Metadata(4, 2),
    Metadata(5, 2),
    Metadata(6, 2),
...]
我想做的是能够迭代这个数组,但是基于
res\u id
获取块(所有数据都是
res\u 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> 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)]
在Julia 1.0中如何实现这一点,考虑到我通常也需要迭代数组以逐元素获取数据?

您可以像这样迭代数组:

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> 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)]

听起来您需要一个
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

从变量的名称来看,您似乎是在从某个计算过程中收集数据。通常情况下,您使用
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      │

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

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

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
这使我能够适应“跳过的”resu id(如从1跳到3等),甚至可以根据resu id以外的其他未来特征(如字符串或Int64以外的类型)对元数据对象进行分组。虽然它可能不是很有效率,但它很有效

然后可以通过以下方式迭代向量{Metadata}:

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

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

使用

for i in x
    # stuff
end
这就是写作的简写

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

有关详细信息,请参见。

但在这种情况下,我不知道只有两种类型的res_id可供选择,当您在1:2中为I说
。如何找出数组中有多少种独特的res_id类型。如果他们有“差距”,比如1,3,4?谢谢,这似乎很有用。但是,我不知道将类型
子数据帧
合并起来是否会缓解我的问题。不过,谢谢你的建议!您总是可以这样做:
用于数据帧中的组。(groupby(data,:res_id))
然后您就有了一个
数据帧
sy您应该得到这样的唯一值
unique(getfield.(data,:res_id))
。永远不要在数组上使用完全扫描进行搜索(除非它只有3个或多个元素)。而是使用
集合
,您的代码将无法与
数据=[元数据(1,1)、元数据(2,3)、元数据(3,1)]
一起工作。您应该有一个单循环,并使用
Dict{Int64,Vector{MetaData}
感谢您的反馈!我本想在另一个问题中发布这个答案,但我觉得它在这里仍然是相关的,所以我将把它留下。