【问题标题】:Julia MetaCollection: implement collection of collectionsJulia MetaCollection:实现集合的集合
【发布时间】:2024-01-24 01:26:01
【问题描述】:

在 Julia 中,我想实现一个包含(异构)集合集合的结构。 迭代和索引的语义应该是直观的,即遍历第一个集合,然后继续下一个集合,直到完成。 我正在寻找实现相关基本功能(例如长度、按索引访问和迭代)的最佳方法。 理想情况下,我想重用预先存在的实用程序函数(例如 Iterators.flatten),而不是手动进行边界检查和索引。

这是我目前所拥有的:长度函数很简单,但我被困在索引和迭代上

struct MetaCollection
    collections::Vector
end

Base.length(meta_collection::MetaCollection) = sum(length.(meta_collection.collections))

function Base.iterate(meta_collection::MetaCollection, state::Int64=1)
    # Base.iterator should not return another iterator, but something along these lines
    return ... Iterators.flatten(meta_collection.collections...)
end

Base.getindex(meta_collection::MetaCollection, i::Int64) = ...

使用示例可能类似于

mc = MetaCollection([["a","b","c"],[1,2,3]])

@test length(mc) == 6
@test mc[5] == 2
for x in mc println(x) end

【问题讨论】:

  • 也许看看实现数组类型数组的github.com/JuliaDiffEq/RecursiveArrayTools.jl 会很有用。
  • 顺便说一句,我假设对于任意集合,您将面临一个非常重要的问题。对于某些集合,length 甚至没有定义。见迭代界​​面:docs.julialang.org/en/latest/manual/interfaces/…。本着这种精神,getindex 真的不是 collection 之类的,而是 array 之类的。以Set 为例。它显然是一个集合,但不可索引。
  • 我想我想要的是介于两者之间的东西:我希望“集合”比数组更通用(包括可迭代的自定义类型等),但我假设子集合都实现了我想为元集合实现的方法(例如长度、getindex 等)。
  • RecursiveArrayTools.jl 对迭代很有用,谢谢
  • 一个小的改进是将boundaries 存储为结构的一个字段。您可以为自动计算它们的结构编写一个单独的构造函数。然后索引会更快(如果你多次这样做)。

标签: indexing collections iteration julia


【解决方案1】:

用我想出的和从 cmets 那里学到的东西来回答我自己的问题

struct MetaCollection
    collections::Vector
end

Base.length(meta_collection::MetaCollection) = sum(length.(meta_collection.collections))

function Base.getindex(meta_collection::MetaCollection, i::Int64)
    boundaries = cumsum(vcat([0], length.(meta_collection.collections)))
    i_c = searchsortedfirst(boundaries, i) - 1
    return meta_collection.collections[i_c][i-boundaries[i_c]]
end

# function Base.iterate(meta_collection::MetaCollection, state::Int64=1)
#     return state <= length(meta_collection) ? (meta_collection[state], state+1) : nothing
# end

# adapted from RecursiveArrayTools.jl
Base.iterate(meta_collection::MetaCollection) = iterate(Iterators.flatten(meta_collection.collections))
Base.iterate(meta_collection::MetaCollection, state) = iterate(Iterators.flatten(meta_collection.collections), state)

【讨论】:

    最近更新 更多