Юлия МетаКоллекция: внедрить коллекцию коллекций - PullRequest
1 голос
/ 15 октября 2019

В Джулии я хочу реализовать структуру, которая содержит коллекцию (гетерогенных) коллекций. Семантика итерации и индексации должна быть интуитивно понятной, то есть работать с первой коллекцией, затем переходить к следующей коллекции, пока не будет выполнено. Я ищу лучшие способы реализации связанных базовых функций, таких как длина, доступ по индексу и итерации. В идеале я хотел бы повторно использовать уже существующие служебные функции (такие как 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

1 Ответ

1 голос
/ 18 октября 2019

Отвечая на мой вопрос с тем, что я придумал и узнал из комментариев

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