v7. Задачка по программированию. НайтиЭлементПоДате(Спр, ДатаДок)

Автор Пиит, 16 апреля 2024, 12:33

« назад - далее »

Пиит

Цитата: xav от 27 апреля 2024, 23:01Немного припозднился, но я только сегодня узнал о существовании задачи. Может и моё решение на что-нибудь сгодится)

Вот так бывало у нас на уроках математики. Стоят у доски ребята, расписывают решения свои простынями до самого плинтуса, и тут вызвется к доске какой-нибудь парень, дескать и у него есть кое-какие мысли. Тихий такой парень, звёзд с неба не хватает, сидит обычно за партой, в окно поглядывает, рисует чего-то в тетрадке, а тут выходит он к доске, черканул две строчки, и тишина. И вот уже в Классе начинается гул: "ни хрена себе", "а так можно было?", "ну ты даёшь", "да ты гений, брат". И Классная наша, Валентина Владимировна, женщина простая, деревенская, в такие моменты могла подзабыть правила приличия, и высказать свою оценку ученику: "а я то думала, что ты тупой, Эдик".
На самом деле это тогда был не Эдик, а Вадик, или Вовчик, суть от этого не меняется. В таких случаях весь Класс единогласно соглашался, что его решение достойно первого места на местном конкурсе математической красоты.

Так и здесь, у нас, я двумя руками буду голосовать, что это решение, на XBase, не только оригинальное, но и очень красивое. Всего одна итерация, что ж может быть лучше.
Я так вообще получил очередной удар, ниже пояса, всю жизнь полагал, что XBase даже не может открыть родную таблицу ИБ, всегда блокируя её на запись, дескать только для обмена данными это гаджет. Как говорит коллега Злоп, семёрка неисчерпаема, как атом.
Снимаю шляпу, коллега xav!

Forum123

Цитата: Пиит от 29 апреля 2024, 10:09Так и здесь, у нас, я двумя руками буду голосовать, что это решение, на XBase, не только оригинальное, но и очень красивое. Всего одна итерация, что ж может быть лучше.

Для работы с DBF и CDX конйигураций 1С 7.7 использую проект https://github.com/harbour/core.
API для использования CDX полностью поддерживает все возможности (в 1С работа с CDX не всю функциональность поддерживает).
Конечно API позволяет использовать CDX 1С.
Разработал возможность использования для DBF нескольких CDX.
Например одна CDX от 1С, а вторая с какими-либо индексами которых в CDX от 1С нет.

Но ИМХО всё это баловство, хотя и 100% функционирует.
В основном API для работы с конфигурацииями 1С мне нужна было лишь для тестирования разрабатываемого API.
Желания разработать а-ля 1С 7.7 никогда не было, хотя с использованием harbour это вполне возможно.
Давно разработал API для работы с любыми объектами конфигураций 1С 7.7.
Но как сказал ранее мне это API нужно лишь для тестирования разрабатываемого API, которое к 1С никакого отношения не имеет.

Ещё раз акцентирую то, что имеется великолепный проект https://github.com/harbour/core.

Пиит

Хочу черкануть пару слов о решении этой задачи на Запросе.

В случае, если есть полная уверенность в том, что записи в справочник внесены в хронологическом порядке, вполне работоспособным будет следующий код:
ТекстЗапроса = "
|ТекущийЭлемент = Справочник.Тестовый.ТекущийЭлемент;
|ДатаЗнач = Справочник.Тестовый.ДатаЗнач;
|Условие(ДатаЗнач <= ДатаДок);";
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Результат = Запрос.ТекущийЭлемент;
КонецЕсли;
Фишка здесь в отсутствии в Запросе Группировки как таковой, и этом случае Запрос вернёт только одну итоговую запись, с готовым результатом. Но это только при соблюдении вышеказанного условия. Дело здесь в том, что Запрос проходит справочник только по порядку ID, фактически по хронологии создания записей, и если Элемент с более ранней ДатаЗнач внесён позже, задним числом, то это решение работать не будет, и придётся ввести Группировку, что увеличит время Запроса примерно в 2.5-3 раза:
ТекстЗапроса = "
|ТекущийЭлемент = Справочник.Тестовый.ТекущийЭлемент;
|ДатаЗнач = Справочник.Тестовый.ДатаЗнач;
|Условие(ДатаЗнач <= ДатаДок);
|Группировка ТекущийЭлемент Упорядочить По ТекущийЭлемент.ДатаЗнач;";
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Если Запрос.Группировка(1, -1) = 1 Тогда
        Результат = Запрос.ЗначениеГруппировки(1);
    КонецЕсли;
КонецЕсли;
В любом случае, количество итераций при Запросе равно количеству Элементов Справочника, вне зависимости от того, индексируется ДатаЗнач или нет, поэтому эти решения востребованы уж точно не будут.
Сам по себе Запрос - это очень интересный объект в семёрке, но к сожалению, не был как следует доработан, и вызывает, конечно, массу нареканий. Но и в нём есть фишки, так, например, режим запроса БезИтогов фактически даёт в распоряжение N-мерную Функцию, и с помощью метода Получить(<Измерение1>,...,<ИзмерениеN>) эти брюки превращаются в РегистрСведенийV8.

Пиит

Спасибо, друзья, всем, кто уделил своё внимание этой теме. Как организатор, я обязан подвести некоторые итоги этого мероприятия.

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

Во-первых, мы все разные, каждый со своим опытом, своими творческими подходами,  со своим уникальным устройством полушарий. Поэтому каждому из нас есть чем поделиться с коллегами. Вот, бывает и такое, что казалось бы, ничем тебя уже в жизни не удивишь, ан нет, получи и распишись. Такой опыт общения всегда полезен.

Во-вторых, и как следствие, на примере одной ничем не примечательной задачи мы смогли убедиться, что универсальных подходов и решений не бывает. Как и в жизни, нет одной волшебной таблетки от всех болезней. В одних условиях, на базе SQL, лучшим решением будет прямой запрос от Алексея Леонидовича, в других это вполне может быть и ADODB from Trad, и XBase from Xav с известными ограничениями, а общем случае и прямой перебор коллеги Злопа даёт тоже неплохие результаты. Но ведь здесь и не все решения представлены. Я уверен, что будь здесь Александр Орефков, он бы предложил к нашим услугам свой 1sqlite, а Владимир Ходаков, усмехнувшись, достал бы из кармана свой Ext на CodeBase и уделал бы всех в одну итерацию в монопольном режиме. Наверняка мог бы придумать что-нибудь и Анатолий Щербаков на своём DBNet.

В общем, как и следует говорить в таких случаях, победила дружба.

И в завершении, как обычно, по традиции, небольшой спич.
Написал я Щербакову письмо, недели две назад, про исходники спрашивал. Пока он не ответил, и боюсь, что отвечать не будет. Когда-то я его обидел, хоть он сам и не знает об этом. Обошёл я его своим вниманием, не поддержал, не принял участие в тестировании его работ, не сказал ему, какой он молоток. А ведь сегодня все мои клиенты работают на его DBNet. А он, Анатолий Викторович, ведь и движок хотел сменить, полность переписал dblang на SQLite. Но в какой-то момент остановился. Мне кажется, что у него тогда просто опустились руки. Подумал он, а кому это вообще я всё делаю, и плюнул в конце концов, на всё и вся.

И вот, здесь и сейчас, я хотел бы пожелать всем Творцам не опускать руки, творите и знайте, что к вам "не зарастёт народная тропа".
Со светлой Пасхой вас, друзья, налегайте на свячёное и много не пейте.
И почаще читайте хорошие Коды, например, Александра Сергеевича:
...
Веленью Божию, о Муза, будь послушна,
Обиды не страшась, не требуя венца,
Хвалу и клевету приемли равнодушно
И не оспоривай глупца...

Злоп

Угу. Все верно.
Код без нештатных возможностей и который работает в любой ситуации и с вполне приемлемым временем исполнения - пока один. Так что ухожу непобеждённый ;-)

Djelf

Цитата: Пиит от 05 мая 2024, 00:06на базе SQL, лучшим решением будет прямой запрос от Алексея Леонидовича
Он же не только на SQL работает, но и на DBF тоже (через 1sqlite).
Но у него есть недостаток: разбор "прямого запроса" и выпрямление его в еще более прямой запрос (в "нативный запрос", позвольте так высказаться) занимает зачастую значительно больше времени, чем выполнение "нативного запроса".
Из-за этого я у него попросил вывод конечного парсера и он это сделал. Это получилось удобно, но пользовался я этим недолго - подкачал скилы и стало без надобности, тем более что sqlite стал значительно круче, но "прямой запрос" об этом то и не знает...

Алгоритм Злопа в победителях гонки, по условиям задачи (без ВК) и кросплатформенно (это заявлено не было, но видимо подрозумевалось).

А другого нет и быть не может.

З.Ы. 1sqlite в DBF базах однозначно рулит! Раз в 10 быстрее с LIMIT 1, нам ведь сортировка в индексе не требуется, она уже есть, т.е. первое попавшееся поле по индексу и мы поймали дату.

З.Ы.Ы. Насчет черного запроса я лучше промолчу, это дикое уродство (по современным меркам) в клюшках. Не осуждаю, это было давно и парсеры были в зачаточном состоянии.


Djelf

АЛьФ, а можно сделать в Сервис замер Пикосекунд?  ;D
Мы тут уже нули с нулевыми Наносекундами пытаемся сравнивать, а они все нулевые  :o
Я не понимаю, что тут ускорять, кроме отказа от 1С:7.7:Запрос...

Пиит

Цитата: Djelf от 05 мая 2024, 15:43... можно сделать в Сервис замер Пикосекунд...

В этом нет необходимости.
Когда проводят школьные олимпиады, для тестирования решений используют заранее подготовленный набор данных, в нашем случае можно 1000 раз прогнать через цикл с ДатаДок, начиная с ВоксресенияГосподня, наращивая аргумент 366 днями или ещё каким-нибудь способом, например, 365++ в каждом цикле.

Djelf

Ну ладно, Запрос так запрос... Вспомнил фишку клюшечных запросов.
Перем Счетчик;
//*******************************************
Функция Счетчик()
	Счетчик=Счетчик+1;
	Возврат Счетчик;
КонецФункции
//*******************************************
Функция ПоискЭлементаПоДате(Знач ДатаДок)
	Счетчик = 0;
	ТекстЗапроса = "
	|ТекущийЭлемент = Справочник.Тестовый.ТекущийЭлемент;
	|ДатаЗнач = Справочник.Тестовый.ДатаЗнач;
	|Условие(ДатаЗнач>=ДатаДок);
	|Условие(Счетчик()=1);
	|";
	Запрос=СоздатьОбъект("Запрос");
	Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
		Возврат Запрос.ТекущийЭлемент;
	КонецЕсли;
КонецФункции
В монопольном режиме со Счетчиком в 10 раз быстрее, в разделенном всего в  2 раза, ну и конечно без Счетчика вернет самую последнюю запись, но зато это позволяет определить порядок ускорения.

Злоп

Тут непонятно в каком порядке будут выбираться элементы.
И как например сработать на условие <=

Пиит

Цитата: Djelf от 06 мая 2024, 12:27Ну ладно, Запрос так запрос... Вспомнил фишку клюшечных запросов.

так будет так работать только если порядок ID совпадает с порядком ДатаЗнач,
в общем случае нет, попробуйте в тестовой базе первый попавшийся результат поставить позже следующего по порядку ДатаЗнач, и Запрос вернёт в следующий раз все равно это значение, а не следующее по порядку ДатаЗнач

Злоп

Тут непонятно в каком порядке в общем случае будут выбираться элементы.
И как, например, сработать на условие <=

Злоп


Djelf

Цитата: Пиит от 06 мая 2024, 14:16так будет так работать только если порядок ID совпадает с порядком ДатаЗнач,

Насколько я знаю принципы выборки, по коду 1sqlite, и копанием в кишках 1С, так быть не должно.
Выборка без индекса идет по ROWID, а не по ID (путать ROWID и ID не стоит).

В данном случае на поле ДатаЗнач стоит флаг Сортировка, следовательно есть индекс.

Я не копал как работает 1С:Запрос, это в принципе бессмысленно, но работать он должен так:

1. Сначала Запрос должен или может (в этом случае должен) увидить что есть индекс по ДатаЗнач и условие по ДатаЗнач.
2. Затем Запрос накладывает фильтр по индексу и сливает данные во временный файл DBF по индексу с наложеным фильтром (иначе работать было бы невозможно из-за диких тормозов).
3. После этого во временном DBF оказываются (уже частичные) данные, упорядоченные по индексу, т.е. по новому ROWID, а не по ID.
4. Выборка из временного файла идет по порядку записей, а они в данном случае должны быть изначально отсортированы по индексу.
5. Первая запись является первой и единственно верной (в условиях задачи).

Заполнение таблицы дат было же рандомное (для исключения глюка эффекта выборки по неизвестному ID).
Данные выборки в #83 соответствует данным полученным из 1sqlite. Вроде гипотеза доказана...

Злоп