Блог

    Caché (Кашэ́) — промышленная высокопроизводительная, объектная система управления базами данных, интегрированная с технологией разработки веб-приложений. Единая архитектура данных Caché позволяет разработчикам использовать одновременно объектный, реляционный (SQL) и прямой (NoSQL) доступ к одним и тем же данным, хранение которых обеспечивается ориентированным на транзакции многомерным ядром СУБД.

    http://www.intersystems.ru/cache/

Последние записи


Теги

Информация

Реализация интервально-ассоциативного массива в СУБД Caché

добавлено: 14 апр 15
понравилось:0
просмотров: 812
комментов: 0

теги:

Автор: servit

Этот же пост доступен и на хабре.

Пост написан на основе статьи на хабре: Интервально-ассоциативный массив.

Поскольку изначальная реализация основана на слайсах (срезах) питона, то для кашеваров нелишним будет статья: Всё, что Вы хотели знать о слайсах.
Примечание:
Но надо заметить, что полный аналог функциональности срезов питона в Caché не был реализован, так как задачи такой не стояло.
И, конечно, немного теории: Дерево Интервалов (Отрезков).

Итак, приступим сразу к примерам.

В целом всё (почти) как в питоне.

Легко назначить:

i=##class(test.intervalmap).%New()
i.%("08:00","12:00","Иванов")
i.%("12:00","16:00","Петров")

Как узнать кто дежурил в 13:51 ?

i.%Get("13:51"),!
Петров

Легко просмотреть поэлементно полный список (для тех, кто привык мыслить "глобально"):

%=i.% zw %
%("08:00","12:00")="Иванов"
%("12:00","16:00")="Петров"

...или одной строкой:

i.Display(),!
[08:00, 12:00] => Иванов, [12:00, 16:00] => Петров

Удаление как по частям:

i.%("15:00","16:00")
i.Display(),!
[08:00, 12:00] => Иванов, [12:00, 15:00] => Петров

...так и целиком:

i.%("12:00","16:00")
i.Display(),!
[08:00, 12:00] => Иванов

Перекрывание ключей должно обрабатываться корректно:

i.%("11:00","15:00","Сидоров")
i.Display(),!
[08:00, 11:00] => Иванов, [11:00, 15:00] => Сидоров

Cоседние ключи с одинаковыми значениями должны склеиваться автоматически. Например, если вы назначили Сидорову подежурить так же с 15 до 17, то навряд ли это должно быть две смены подряд, скорее - одна более длинная:

i.%("15:00","17:00","Сидоров")
i.Display(),!
[08:00, 11:00] => Иванов, [11:00, 17:00] => Сидоров

Добавим пару записей:

i.%("17:00","20:00","Петров")
i.%("21:00","23:00","Сидоров")
i.Display(),!
[08:00, 11:00] => Иванов, [11:00, 17:00] => Сидоров, [17:00, 20:00] => Петров, [21:00, 23:00] => Сидоров

Часто возникает задача урезать расписание, оставив из нескольких идущих подряд элементов только последние. Например, нужно узнать, кто закрывал рабочий день:

i.Shrink()
i.Display(),!
[08:00, 20:00] => Петров, [21:00, 23:00] => Сидоров

Этот же метод можно использовать для проверки полностью ли ваше расписание охватывает рабочий день.

Дополнение

  • Была учтена небольшая ошибка в исходном коде по склейке соседних ключей, а именно:

    Питон:

    >>> timetable = intervalmap()
    >>> timetable[:] = 'Иванов'
    >>> timetable['11:00':'13:00'] = 'Иванов'
    >>> print timetable
    {[None, '13:00'] => 'Иванов', ['13:00', None] => 'Иванов'}
    
    COS:

    i=##class(test.intervalmap).%New()
    i.%(,,"Иванов")
    i.%("11:00","13:00","Иванов")
    i.Display(),!
    [None, None] => Иванов
  • Одинаковые ключи в паре, как в исходном коде, здесь не допускаются, но вы для себя можете включить их обратно.
  • Конечно же в качестве ключей могут выступать любые числовые/строковые значения. Единственное, нужно следить, чтобы все они в рамках одного массива (объекта) были однотипны.
    Например:

    i=..%New()
    i.%(9,,"!")
    i.%(,5,"Hello")
    i.%(6,7,"World")
    i.Display(),!
    [None, 5] => Hello, [6, 7] => World, [9, None] => !

    i.Reset()
    i.%(,$zdh("24.10.2005"),"A")
    i.%($zdh("11.11.2005"),$zdh("17.11.2005"),"B")
    i.%($zdh("30.11.2005"),,"C")
    i.Display(),!
    [None, 60197] => A, [60215, 60221] => B, [60234, None] => C
  • И напоследок ещё один пример посложнее:

    i.Reset()
    i.%(,,$c(8734))
    i.%(10,11,"Иванов")
    i.%(12,13,"Иванов")
    i.%(14,16,"Петров")
    i.%(11,15,"Иванов")
    i.%(8,12,"Сидоров")
    i.%(20,21)
    i.%(22,,"Сидоров")
    i.Display(),!
    + Результат под спойлером
    [None, 8] => ∞, [8, 12] => Сидоров, [12, 15] => Иванов, [15, 16] => Петров, [16, 20] => ∞, [21, 22] => ∞, [22, None] => Сидоров
    Больше примеров вы найдёте в исходном коде.
  • Код тестировался на версии Caché 2015.1, но переделать класс для предыдущих версий не составит особого труда.
И как всегда, улучшайте, дополняйте, исправляйте класс test.intervalmap под ваши нужды.

Комментарии




Необходимо войти на сайт, чтобы оставлять комментарии