[Request for help] CompositeRange<T>
От: Sinix  
Дата: 30.09.16 20:29
Оценка:
Народ, ай нид хелп!
Наконец добил черновой вариант CompositeRange<T> — штуки для операций над составными диапазонами.

Для затравки:
            var range = Range.Create(1, 2, "Key1")
                .ToCompositeRange()
                .Union(Range.Create(5, 10, "Key2"))
                .Except(Range.Create(7, 8))
                .Intersect(2, 9);
            AreEqual(range.ToInvariantString(), "[2..9]: { 'Key1':[2..2]; 'Key2':[5..7); 'Key2':(8..9] }");


            range = range.Union(Range.Create(7, 8, "Key1"));
            AreEqual(range.ToInvariantString(), "[2..9]: { 'Key1':[2..2]; 'Key2':[5..7); 'Key1':[7..8]; 'Key2':(8..9] }");


            range = range
                .Except(7, 8)
                .Union(Range.Create(7, 8, "Key2"));
            AreEqual(range.ToInvariantString(), "[2..9]: { 'Key1':[2..2]; 'Key2':[5..9] }");


Код лежит в Experimental, тесты рядышком.

Сразу предупреждаю — код полный отстой в смысле производительности, по аллокациям — вообще адов ад.

Это всё будет потихоньку допиливаться, пока вопрос в другом: что нравится / не нравится, чего не хватает, какие предложения/пожелания — всё вэлкам!
Re: [Request for help] CompositeRange<T>
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.09.16 20:32
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Народ, ай нид хелп!

S>Наконец добил черновой вариант CompositeRange<T> — штуки для операций над составными диапазонами.

А можно сразу вопрос — чем это лучше просто Range<T>[]?
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK Blog
Re[2]: [Request for help] CompositeRange<T>
От: Sinix  
Дата: 30.09.16 20:38
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>А можно сразу вопрос — чем это лучше просто Range<T>[]?


Только готовыми операциями над наборами диапазонов, больше ничем. А, ну и null ref exception не будет
Понятно, что то же самое можно сделать и методами-расширениями поверх Range<T>[], но тогда операции получаются дороговастыми.

Для CompositeRange можно срезать кучу углов, т.к. поддиапазоны отсортированы + известны общие границы всего диапазона, для массива всё скатывается к полному перебору и к O(n^2) в самом запущенном случае.
Re[3]: [Request for help] CompositeRange<T>
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.09.16 20:57
Оценка: 23 (1)
Здравствуйте, Sinix, Вы писали:

AVK>>А можно сразу вопрос — чем это лучше просто Range<T>[]?

S>Только готовыми операциями над наборами диапазонов, больше ничем.

Известное правило Мейера говорит, что все методы, которые можно сделать свободными функциями, нужно сделать свободными функциями.

S>Для CompositeRange можно срезать кучу углов, т.к. поддиапазоны отсортированы


Ну то есть фишка в том, что внутри диапазоны всегда отсортированы? Тогда понятно.

Из того что мне требовалось:
1) Мне нужен механизм ассоциаций с диапазонами некоей допинформации. Т.е. Range<T, TValue>
2) Алгоритм, который гарантирует отсутствие наложения диапазонов, но при этом все границы должны сохраняться, т.е. это не просто мердж. К этому еще необходимо склеивать допинформацию (Т.е. на входе Range<T, TValue>[], на выходе Range<T, TValue[]>[]). Вот как оно выглядит у меня (я, вроде, уже постил):
internal static IEnumerable<RangeDescriptor> NormalizeRanges(IEnumerable<Transition> source)
{
    var ranges =
        source
            .SelectMany(t => t.Ranges.Select(r => new {r.Start, r.End, t.Target}))
            .ToArray();
    var points =
        ranges
            .SelectMany(
                r =>
                    new[]
                    {
                        new {Pos = (int)r.Start, Targets = new List<State>()},
                        new {Pos = r.End + 1, Targets = new List<State>()}
                    })
            .OrderBy(p => p.Pos)
            .ToArray();
    foreach (var range in ranges)
        foreach (var point in
                points
                    .SkipWhile(p => p.Pos < range.Start)
                    .TakeWhile(p => p.Pos <= range.End))
            point.Targets.Add(range.Target);
    return
        points
            .Zip(points.Skip(1), (p1, p2) => new {Start = p1, End = p2})
            .Where(r => r.Start.Targets.Any() && r.Start.Pos < r.End.Pos)
            .Select(
                r =>
                    new RangeDescriptor(
                        new CharRange(
                            (ushort) r.Start.Pos,
                            (ushort) (r.End.Pos - 1)),
                        r.Start.Targets.ToArray()));
}

Обсуждение алгоритма
Автор: AndrewVK
Дата: 20.02.14

Как это правильно генерализовать я
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK Blog
Re[4]: [Request for help] CompositeRange<T>
От: Sinix  
Дата: 30.09.16 21:03
Оценка: 9 (1)
Здравствуйте, AndrewVK, Вы писали:



AVK>Из того что мне требовалось:

AVK>1) Мне нужен механизм ассоциаций с диапазонами некоей допинформации. Т.е. Range<T, TValue>
Уже есть, прям в стартовом сообщении пример.

AVK>2) Алгоритм, который гарантирует отсутствие наложения диапазонов, но при этом все границы должны сохраняться, т.е. это не просто мердж.

Для проверки — тоже есть, свойство IsMerged.

Для получения всех взаимопересечений поддиапазонов есть GetIntersections(), если не оно — подумаю позже (вечер, влом уже).
Re[5]: [Request for help] CompositeRange<T>
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.09.16 21:18
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Уже есть, прям в стартовом сообщении пример.


Прекрасно.

S>Для получения всех взаимопересечений поддиапазонов есть GetIntersections(), если не оно — подумаю позже (вечер, влом уже).


Посмотри по последней ссылке, там более полное объяснение требований. Можно ли их реализовать через GetIntersections я так сходу не могу сказать. Так вроде похоже, хотя неплохо было бы вариант добавить с проекцией вместо готовой структурки RangeIntersections. Ну и мой алгоритм (он основан на том что Коля предложил
Автор: Кодт
Дата: 23.02.14
) вроде бы покороче, не?
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK Blog
Re[6]: [Request for help] CompositeRange<T>
От: Sinix  
Дата: 30.09.16 21:37
Оценка:
Здравствуйте, AndrewVK, Вы писали:

S>>Для получения всех взаимопересечений поддиапазонов есть GetIntersections(), если не оно — подумаю позже (вечер, влом уже).

AVK>Посмотри по последней ссылке, там более полное объяснение требований.
Я посмотрел — оно и есть по-моему.
Результаты вот тут.

AVK>Ну и мой алгоритм (он основан на том что Коля предложил
Автор: Кодт
Дата: 23.02.14
) вроде бы покороче, не?

Я в него пока не вьехал (и не пытался мозг уже всё), но по-моему он не будет работать с произвольными типами границ.

Ну и твой O(n^2) (если я нигде не протупил) против моего варианта (O(n*log(n)) и +log(n) по памяти) тож как-то не ок. Но это уже десятый-сотый вопрос, сначала надо с поведением определиться, а затем уже код ускорять.

А то некоторые требования (например, разрешать кучу одинаковых диапазонов с разными ключами и не учитывать порядок ключей при сравнении) здорово по производительности бьют и ничего с этим не сделаешь.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.