После упразднения блогов стало негде хранить небольшие короткие решения, сделанные в ходе обсуждения интересных задач других авторов. Решил собрать все такие свои решения в одну статью, которую надеюсь постепеннно дополнять. Большинство решений выполнено в стиле "минимализма" и, наверное, не могут служить примером для подражания. То есть это такие сублиматы кода, которые перед употреблением, возможно, следует еще "размочить" комментариями.
С другой стороны, есть конкурсы по "гольфу" для программистов, где требуется решить задачу с использованием минимального количества команд. Приведенные решения можно использовать для соответствующей тренировки.
Решения приведены с минимумом пояснений или вообще без них. Заинтересовавшимся стоит посмотреть ссылки на исходные обсуждения или задать вопросы здесь. Постараюсь на них ответить.
1. Квайн (программа, распечатывающая свой собственный текст)
С="С="";Л=Лев(С,3);П=Сред(С,3);Сообщить(Л+Л+П+П)";Л=Лев(С,3);П=Сред(С,3);Сообщить(Л+Л+П+П)
Процедура КВН(К)С="Процедура КВН(К)С="";Л=Лев(С,19);П=Сред(С,19);Сообщить(Л+Л+П+П)КонецПроцедуры";Л=Лев(С,19);П=Сред(С,19);Сообщить(Л+Л+П+П)КонецПроцедуры
2. Колонка сжато
Суть задачи в том, что в колонке табличной части находятся целые числа. Необходимо "сжать" ряд чисел, заменив подряд идущие числа их диапазоном.
Например: 1, 3, 4, 5, 7, 10, 11, 12, 16 должно превратиться в 1, 3-5, 7, 10-12, 16.
Функция КолонкаСжато(ДокументСсылка, ИмяТабличнойЧасти, ИмяКолонки, Слэш = ",", Тире = "-")
Запрос = Новый Запрос("ВЫБРАТЬ Различные " + ИмяКолонки + " ИЗ Документ." + ДокументСсылка.Метаданные().Имя + "." + ИмяТабличнойЧасти + " ГДЕ Ссылка = &Ссылка Упорядочить ПО " + ИмяКолонки);
Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);
Ряд = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку(ИмяКолонки);
Если Ряд.Количество() = 0 Тогда Возврат ""
КонецЕсли;
Ряд.Добавить(0); Ряд.Добавить(0);
Сжато = Строка(Ряд[0]);
Для ё = 1 По Ряд.Количество() - 3 Цикл
Если Число(Ряд[ё + 1]) - Число(Ряд[ё - 1]) <> 2 Тогда
Сжато = Сжато + Слэш + Строка(Ряд[ё])
ИначеЕсли Число(Ряд[ё + 2]) - Число(Ряд[ё]) <> 2 Тогда
Сжато = Сжато + Тире
КонецЕсли
КонецЦикла;
Возврат СтрЗаменить(Сжато, Тире + Слэш, Тире)
КонецФункции
3. Сортировка слиянием
Дано два отсортированных по возрастанию массива А и В. Необходимо вывести по возрастанию все элементы этих массивов.
ёж = 0;
Для уж = 0 По А.Количество() + В.Количество() - 1 Цикл
що = (уж - ёж) = В.Количество() ИЛИ ёж < А.Количество() И А[ёж] < В[уж - ёж];
Сообщить(?(що, "а" + ёж + "=" + А[ёж], "в" + (уж - ёж) + "=" + В[уж - ёж]));
ёж = ёж + що
КонецЦикла
ё = 0;
Для Сч = 1 По А.Количество() + В.Количество() Цикл
ж = (Сч - 1 - ё) = В.Количество() ИЛИ ё < А.Количество() И А[ё] < В[Сч - 1 - ё];
Сообщить(?(ж, "А[" + ё + "]=" + А[ё], "В[" + (Сч - 1 - ё) + "]=" + В[Сч - 1 - ё]));
ё = ё + ж
КонецЦикла
4. Срезы последних (интерполяция периодических сведений)
"Срезы последних" - одна из первых задач, на которой спотыкается начинающий программист 1С. Хорошо поняв идею виртуального регистра "Срез последних", мы ожидаем такой же простоты, если задана не одна дата, на которую нужно выбрать сведения, а несколько. Но, увы, приходится использовать два запроса. В первом мы выбираем ближайшие в прошлом даты, на которые были установлены значения, а во втором по датам определяем сами значения.
Оказывается, при большом желании можно уложиться в один запрос. Вот этот запрос для примера решения задачи "Продажи с выводом цены заданного типа, действующей на момент отгрузки".
ВЫБРАТЬ
Продажи.Период,
Продажи.Контрагент,
Продажи.Номенклатура,
СУММА(Продажи.КоличествоОборот) КАК Количество,
СУММА(Продажи.СтоимостьОборот) КАК Стоимость,
МИНИМУМ(РАЗНОСТЬДАТ(ЦеныНоменклатуры.Период, Продажи.Период, ДЕНЬ) * &Много + ЦеныНоменклатуры.Цена)
- МИНИМУМ(РАЗНОСТЬДАТ(ЦеныНоменклатуры.Период, Продажи.Период, ДЕНЬ) * &Много) КАК Цена
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, День, ) КАК Продажи
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
ПО Продажи.Номенклатура = ЦеныНоменклатуры.Номенклатура
И (ЦеныНоменклатуры.ТипЦен = &ТипЦен)
И (ЦеныНоменклатуры.Период < = Продажи.Период)
СГРУППИРОВАТЬ ПО
Продажи.Период,
Продажи.Контрагент,
Продажи.Номенклатура
Идея в том, чтобы вместо поиска периода, на котором начинается актуальная цена, искать саму цену. Для этого подобрана функция, которая "отправляет" цену прошлого периода на свой "эшелон", высота которого зависит от древности цены. Ширина "эшелона" задается параметром "Много" - это величина, гарантированно перекрывающая диапазон изменения цены (1000000, 10000000 и т.п.). После нахождения ближайшей (нижайшей) "летящей" цены, высота соответствующего "эшелона" вычитается и цена "опускается на землю".
Можно подобрать функцию для дат, булевых и строковых значений.
Кроме краткости записи, других достоинств у запроса нет. Минусы - некоторый проигрыш по времени "классическому" запросу из-за большего объема вычислений в группировках, необходимость думать над значением "Много", работа только с простыми типами.
Вообще, вместе с этим, известно четыре способа интерполяции. Интересно было бы провести вычислительный эксперимент по сравнению их эффективности. Пока всегда выигрывал классический способ.
5. ЗначениеСвойства
Для получения значения одного свойства выбранного объекта хватает одной строки кода, которую можно оформить в виде функции или использовать "инлайн"
ЗначениеСвойства = РегистрыСведений.ЗначенияСвойствОбъектов.Получить(Новый Структура("Объект, Свойство", ОбъектСсылка, ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию(ИмяСвойства))).Значение;
6. Остатки на каждый день
Стандартная выборка из виртуального регистра остатков и оборотов не показывает остатки на периодах, в которых нет оборотов. В СКД, то есть вне запроса проблема легко решается, а для использования внутри запроса приходится "городить огород". У многих это выливается в несколько запросов, тогда как можно обойтись и одним. Остатки здесь получаются суммированием оборотов. По тому же принципу платформа рассчитывает остатки внутри периода хранения итогов.
ВЫБРАТЬ РАЗЛИЧНЫЕ
КурсыВалют.Период
ПОМЕСТИТЬ Дни
ИЗ
РегистрСведений.КурсыВалют КАК КурсыВалют
ГДЕ
КурсыВалют.Период МЕЖДУ &НачалоПериода И &КонецПериода
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Движения.Номенклатура,
ДНИ.Период,
СУММА(ВЫБОР
КОГДА Движения.Период = &НачалоПериода
ТОГДА Движения.КоличествоКонечныйОстаток
ИНАЧЕ ВЫБОР
КОГДА Движения.Период < = ДНИ.Период
ТОГДА Движения.КоличествоОборот
ИНАЧЕ 0
КОНЕЦ
КОНЕЦ) КАК КоличествоКонечныйОстаток
ИЗ
Дни КАК ДНИ,
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, День, , Номенклатура = &Номенклатура) КАК Движения
СГРУППИРОВАТЬ ПО
Движения.Номенклатура,
ДНИ.Период
Правда, здесь рассчитываются остатки на конец каждого дня (это легко поправить, сдвинув даты на -1). Регистр "КурсыВалют" взят для краткости и для разнообразия - все даты внутри периода можно получать и по другому. Классический вариант проигрывает по быстродействию предложенному примерно в 1.5 раза (проверялось на файловой базе УПП).
7. Связывание таблиц значений по ФИФО
Если имеется две таблицы с колонками: Период, Документ, Сумма, то часто возникает задача построения объединенной таблицы "Результат" с колонками Период1, Документ1, Период2, Документ2, Сумма, в которой документы двух таблиц связаны по ФИФО. Чтобы функция Результат.Свернуть("Период1,Документ1", "Сумма") давала первую таблицу, а Результат.Свернуть("Период2,Документ2", "Сумма") - вторую.
Такой задачей, является, например, распределение оплат по отгрузкам.
Вот требуемая функция. Осторожнее, так как она меняет исходные таблицы!
Функция СвязываниеПоФИФО(А, Б, ё = 0, ж = 0) Экспорт
Результат = НовыйТаблицаЗначений("Период1, Документ1, Период2, Документ2, Сумма");
Пока ё < А.Количество() И ж < Б.Количество() Цикл
Сумма = Мин(А[ё].Сумма, Б[ж].Сумма);
ЗаполнитьЗначенияСвойств(Результат.Добавить()
, Новый Структура("Период1, Документ1, Период2, Документ2, Сумма"
, А[ё].Период, А[ё].Документ, Б[ж].Период, Б[ж].Документ, Сумма));
А[ё].Сумма = А[ё].Сумма - Сумма;
Б[ж].Сумма = Б[ж].Сумма - Сумма;
ё = ё + (А[ё].Сумма = 0);
ж = ж + (Б[ж].Сумма = 0)
КонецЦикла;
Возврат Результат
КонецФункции
8. Формирование синонима переменной из идентификатора
Вариант на основе стэйт-машины
Функция Синонимайзер(Имя, Ответ = "", Стэйт = 7, б = "") Экспорт
Для ё = 1 По СтрДлина(Имя) Цикл
а = Сред(Имя, ё, 1);
Стэйт = (НРег(а) <> а) * 4 + Цел(Стэйт / 2);
Ответ = Ответ + ?(Стэйт = 2, НРег(б), ?(ё = 2, ВРег(б), б)) + ?(Стэйт = 4 ИЛИ Стэйт = 5, " ", "");
б = а
КонецЦикла;
Возврат Ответ + б
КонецФункции
Выгодное отличие здесь в том, что символ вырезается из строки и проверяется на регистр только один раз. Если б не надо было первую букву делать заглавной - было бы еще красивее.
9. Сравнение двух строк
Результатом сравнения двух строк является массив, который показывает, что от "От" до "До" позиции строки совпадают (ОК = Истина) или нет.
Функция ТаблицаСравненияСтрок_(С1, С2) Экспорт
Ответ = Новый ТаблицаЗначений; //Ответ = НоваяТаблицаЗначений("От, До, ОК");
Ответ.Колонки.Добавить("От");
Ответ.Колонки.Добавить("До");
Ответ.Колонки.Добавить("ОК");
ЗаполнитьЗначенияСвойств(Ответ.Добавить(), Новый Структура("От, ОК", 1, Сред(С1, 1, 1) = Сред(С2, 1, 1)));
Для ё = 2 По Макс(СтрДлина(С1), СтрДлина(С2)) Цикл
Если Ответ[0].ОК <> (Сред(С1, ё, 1) = Сред(С2, ё, 1)) Тогда
ЗаполнитьЗначенияСвойств(Ответ.Вставить(0), Новый Структура("От, ОК", ё, НЕ Ответ[1].ОК));
Ответ[1].До = ё - 1
КонецЕсли
КонецЦикла;
Ответ[0].До = Макс(СтрДлина(С1), СтрДлина(С2));
Возврат Ответ
КонецФункции
С дихотомией
Процедура РазДва(Ответ, С1, С2, От, До)
Если От + 2 > До И (Сред(С1, От, 1) = Сред(С2, От, 1)) <> (Сред(С1, До, 1) = Сред(С2, До, 1)) Тогда
ЗаполнитьЗначенияСвойств(Ответ.Вставить(0), Новый Структура("От, ОК", До, НЕ Ответ[1].ОК));
Ответ[1].До = От
ИначеЕсли От + 1 < До И Сред(С1, От, До - От + 1) <> Сред(С2, От, До - От + 1) Тогда
РазДва(Ответ, С1, С2, От, Цел((От + До) / 2));
РазДва(Ответ, С1, С2, Цел((От + До) / 2), До)
КонецЕсли
КонецПроцедуры
Функция ТаблицаСравненияСтрок(С1, С2) Экспорт
Ответ = Новый ТаблицаЗначений;
Ответ.Колонки.Добавить("От");
Ответ.Колонки.Добавить("До");
Ответ.Колонки.Добавить("ОК");
ЗаполнитьЗначенияСвойств(Ответ.Добавить(), Новый Структура("От, ОК", 1, Сред(С1, 1, 1) = Сред(С2, 1, 1)));
РазДва(Ответ, С1, С2, 1, Макс(СтрДлина(С1), СтрДлина(С2)));
Ответ[0].До = Макс(СтрДлина(С1), СтрДлина(С2));
Возврат Ответ
КонецФункции
10. Ход конем
http://forum.infostart.ru/forum1/topic78895/message844453/#message84445
Определить количество и поля клеток, доставаемых конем, в зависимости от его положения на доске
ВЫБРАТЬ 1 у, "a" х
ПОМЕСТИТЬ а
ОБЪЕДИНИТЬ ВЫБРАТЬ 2, "b"
ОБЪЕДИНИТЬ ВЫБРАТЬ 3, "c"
ОБЪЕДИНИТЬ ВЫБРАТЬ 4, "d"
ОБЪЕДИНИТЬ ВЫБРАТЬ 5, "e"
ОБЪЕДИНИТЬ ВЫБРАТЬ 6, "f"
ОБЪЕДИНИТЬ ВЫБРАТЬ 7, "g"
ОБЪЕДИНИТЬ ВЫБРАТЬ 8, "h"
;
ВЫБРАТЬ г.х, д.у
ИЗ а а, а г, а д
ГДЕ а.х = &ах И (а.у - г.у) * (а.у - г.у) + (&бу - д.у) * (&бу - д.у) = 5
11. Сгибы листка (задача с собеседования)
Функция возвращает строку, в которой 0 - сгиб от нас, 1 - к нам. Первый параметр - необходимое число сложений, второй и третий параметры служебные. Всего в записи функции 77 символов. Не по-русски потому, что так короче.
function W(k,a=0,b=0)return?(k<1,"",W(k-1,a+b)+a%2+W(k-1,a+1+b,1))endfunction
Если предположить, что число сгибов не может быть отрицательным, то можно сэкономить еще 2 символа. Итого 75 символов. Можно ли короче?
function W(k,a=0,b=0)return?(k,W(k-1,a+b)+a%2+W(k-1,a+b+1,1),"")endfunction
12. Найти кратчайший путь коня между двумя заданными клетками
http://forum.infostart.ru/forum1/topic78895/message839037/#message839037
Первая функция размечает доску, вторая рекурсивно перечисляет пути из конечной точки.
Разметка идет "по спирали". Номер витка (круга) соответствует минимальному расстоянию от начальной точки. На каждом витке неразмеченные клетки просматриваются в паре с каждой клеткой последнего витка. Если расстояние (сумма квадратов разности координат равно пяти) соответствует шагу коня клетка включается в следующий виток (круг). И так пока в круг не попадет конечная клетка. В каждой клетке запоминается массив клеток предыдущего витка, из которых попадают в текущую. Это дает возможность рекурсивно раскрутить пути до начальной точке "при спуске".
Функция Спираль(А, Б, Круг = 0)Экспорт
Поле = НоваяТаблицаЗначений("Х, У, Круг, Связи");
Для К = 0 По 63 Цикл
ЗаполнитьЗначенияСвойств(Поле.Добавить(), Новый Структура("Х, У, Круг, Связи", Цел(К / 8), К % 8, (К = А) - 1, Новый Массив))
КонецЦикла;
Пока Поле[Б].Круг < 0 Цикл
Целина = Поле.НайтиСтроки(Новый Структура("Круг", -1));
Трек = Поле.НайтиСтроки(Новый Структура("Круг", Круг));
Для Каждого С Из Целина Цикл
Для Каждого К Из Трек Цикл
Если (С.Х - К.Х) * (С.Х - К.Х) + (С.У - К.У) * (С.У - К.У) = 5 Тогда
С.Круг = Круг + 1;
С.Связи.Добавить(К.Х * 8 + К.У)
КонецЕсли
КонецЦикла
КонецЦикла;
Круг = Круг + 1
КонецЦикла;
Возврат Поле
КонецФункции
Процедура Спуск(Б, Поле, Знач Путь = "") Экспорт
Путь = Сред("abcdefgh", Б / 8 + 1, 1) + (Б % 8 + 1) + " " + Путь;
Если Поле[Б].Связи.Количество() = 0 Тогда
ЗаполнитьЗначенияСвойств(Пути.Добавить(), Новый Структура("Путь", Путь))
Иначе
Для Каждого К Из Поле[Б].Связи Цикл
Спуск(К, Поле, Путь)
КонецЦикла
КонецЕсли
КонецПроцедуры
13. Функция для превращения строки в дату по форматной строке
Функция СтрокаВДату(Знач ФорматДаты, Знач Дано, Ошибка = Ложь) Экспорт
Попытка
ё = Формат('00010101', "ДФ=" + ФорматДаты) // - необязательная проверка первого правильности параметра
Исключение
Ошибка = Истина;
Возврат '00010101'
КонецПопытки;
Ч = Новый Соответствие;
Для ё = 1 По СтрДлина(ФорматДаты) + 7 Цикл
Ч[Сред(ФорматДаты + "dMyHhms", ё, 1)] = 0 // - инициализация частей даты
КонецЦикла;
Для ё = 1 По 12 Цикл
Дано = СтрЗаменить(Дано, Формат(Дата(1, ё, 1), "ДФ=MMММ"), Формат(ё, "ЧЦ=4; ЧВН=")); // - замена названий месяцев числами
Дано = СтрЗаменить(Дано, Формат(Дата(1, ё, 1), "ДФ=MMМ" ), Формат(ё, "ЧЦ=3; ЧВН="))
КонецЦикла;
Для ё = 1 По СтрДлина(ФорматДаты) Цикл
Ч[Сред(ФорматДаты, ё, 1)] = 10 * Ч[Сред(ФорматДаты, ё, 1)] + Найти("123456789", Сред(Дано, ё, 1)); // - накопление частей даты
Ошибка = Ошибка ИЛИ Найти("dMyHhms", Сред(ФорматДаты, ё, 1)) И НЕ Найти("0123456789", Сред(Дано, ё, 1)) // - необязательная проверка на цифры
КонецЦикла;
Ч["y"] = Ч["y"] + ?(Ч["y"] < 50, 2000, ?(Ч["y"] < 100, 1900, 0)); // - дополнение двух цифр года до четырех
Попытка
Возврат Дата(Ч["y"], Ч["M"], Ч["d"], Ч["H"] + Ч["h"], Ч["m"], Ч["s"])
Исключение
Ошибка = Истина;
Возврат '00010101'
КонецПопытки
КонецФункции
14. Сжатое представление последовательности дат запросом
http://forum.infostart.ru/forum26/topic112033/message1160294/#message1160294
Задача похожа на сжатое представление ряда чисел, только роль чисел играют даты. Дана последовательность дат. Нужно заменить ее последовательностью непрерывных интервалов дат. Вот решение
ВЫБРАТЬ
Даты.Дата,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДатыДо.Дата) КАК Номер
ПОМЕСТИТЬ НомераДат
ИЗ
ВТДаты КАК Даты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТДаты КАК ДатыДо
ПО (ДатыДо.Дата < = Даты.Дата)
СГРУППИРОВАТЬ ПО
Даты.Дата
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
МИНИМУМ(НомераДат.Дата) КАК ДатаНач,
МАКСИМУМ(НомераДат.Дата) КАК ДатаКон
ИЗ
НомераДат КАК НомераДат
СГРУППИРОВАТЬ ПО
ДОБАВИТЬКДАТЕ(НомераДат.Дата, ДЕНЬ, -НомераДат.Номер)
15. Размещение восьми ферзей на шахматной доске для СУБД Oracle
Найти запросом все варианты размещения 8-ми ферзей на шахматной доске, чтобы они не били друг друга.
В Oracle много чего есть, включая рекурсию. Поэтому режение получилось коротким. Задача взята с Хабра из раздела "ненормальное программирование"
http://habrahabr.ru/post/228373/#first_unread
with
x(i) as (select level from dual connect by level < = 8),
q(z, j) as (select '', 1 from dual
union all
select z || y.i, j + 1 from q inner join x y
on not exists(select 1 from x where i < j and (y.i - substr(z, i, 1)) / (j - i) IN (-1, 0, 1)))
cycle z set cyclemark to 'X' default '-'
select translate('a1 b2 c3 d4 e5 f6 h7 g8', '12345678', z) from q where j = 8 + 1
16. Добавить к дате и разность дат
Функции для работы с датами как в языке запросов
Функция ДобавитьКДате(Дата1, Количество, Период) Экспорт
Шаг = Новый Структура("Год, Квартал, Месяц, Неделя, День, Час, Минута, Секунда", 12, 3, 1, -604800, -86400, -3600, -60, -1);
Возврат ?(Шаг[Период] > 0, ДобавитьМесяц(Дата1, Количество * Шаг[Период]), Дата1 - Количество * Шаг[Период])
КонецФункции
Функция РазностьДат(Дата1, Дата2, Период) Экспорт
Шаг = Новый Структура("Год, Квартал, Месяц, Неделя, День, Час, Минута, Секунда", 12, 3, 1, -604800, -86400, -3600, -60, -1);
Возврат Цел(?(Шаг[Период] > 0, Год(Дата2) * 12 + Месяц(Дата2) - 1, '00010101' - Дата2) / Шаг[Период])
- Цел(?(Шаг[Период] > 0, Год(Дата1) * 12 + Месяц(Дата1) - 1, '00010101' - Дата1) / Шаг[Период])
КонецФункции
ну и раз зашла речь о датах...
Функция Квартал
Функция Квартал(Дата) Экспорт
Возврат Цел((Месяц(Дата) - 1) / 3) + 1
КонецФункции
Названия месяцев прописью
Формат(Дата(1, НомерМесяца, 1),"ДФ=ММММ")
Название дней недели прописью
Формат(Дата(1, 1, 2 + НомерДняНедели),"ДФ=дддд")
17. Получение таблицы и массива, заполненных последовательностью чисел от 0 до N-1
Иногда бывает нужно быстро получить готовый массив с последовательностью чисел от 0 до N-1. Например, чтобы пронумеровать строки таблицы значений путем загрузки в нее колонки с номерами строк. Это можно очень быстро сделать, используя "Порождающий запрос". Все необходимые функции очень компактны. Поэтому они приведены здесь.
// Возвращает текст запроса, формирующего таблицу чисел rN с одной колонкой X (eng), содержащую ряд: 0, 1, (N - 1).
function ProtoText(N, M = 1000000000) export
return ?(N > 2
, ProtoText(M - Int(M - Sqrt(N)))
+ strreplace(strreplace(";select top #2 a.X * #1 + b.X X into r#2 from r#1 a, r#1 b", "#2", format(N, "NG=")), "#1", format(M - Int(M - Sqrt(N)), "NG="))
, "select 0 X into r2 union select 1")
endfunction
// Возвращает таблицу, содержащую последовательность чисел: 0, 1, 2, ..., (ЧислоСтрок - 1)
Функция ПоследовательностьЧиселТаблицей(ЧислоСтрок) Экспорт
Запрос = Новый Запрос(СтрЗаменить(ProtoText(ЧислоСтрок), "into r" + format(ЧислоСтрок, "NG="), ""));
Возврат Запрос.Выполнить().Выгрузить()
КонецФункции
// Возвращает массив, содержащий последовательность чисел: 0, 1, 2, ..., (ЧислоЭлементов - 1)
Функция ПоследовательностьЧиселМассивом(ЧислоЭлементов) Экспорт
Возврат ПоследовательностьЧиселТаблицей(ЧислоЭлементов).ВыгрузитьКолонку(0)
КонецФункции
18. Простой трюк для быстрого объединения таблиц значений
Стандартный способ объединения двух таблиц значений заключается в организации цикла, в котором строки второй таблицы приписываются в конец копии первой. Для этого используется следующий простой код:
ОбъединениеТаблиц = Таблица1.Скопировать();
Для Каждого Строка Из Таблица2 Цикл ЗаполнитьЗначенияСвойств(ОбъединениеТаблиц.Добавить(), Строка) КонецЦикла
Все возможности оптимизация данного способа ограничиваются записью в одну строку и выбором таблицы с меньшим количеством элементов в качестве источника добавляемых строк.
Предлагаемый трюк заключается в последовательном выполнении трех действий:
1) Вторая (добавляемая) таблица копируется в таблицу-результат;
2) В начало таблицы результата перед уже скопированной таблицей вставляется столько пустых строк, сколько строк в первой таблице. Таким образом «освобождается место» для первой таблицы;
3) Затем первая таблица помещается на освобожденное место методом выгрузки-загрузки колонок. Фокус в том, что при загрузке колонки в таблицу значений, если загружаемая колонка короче целевой, то оставшиеся элементы целевой колонки не меняются.
Схематичное описание той же последовательности действий приведено на рисунке ниже
Реализация предложенного способа очень проста и выполняется следующим фрагментом программного кода:
ОбъединениеТаблиц = Таблица2.Скопировать();
Для ё = 1 По Таблица1.Количество() Цикл ОбъединениеТаблиц.Вставить(0) КонецЦикла;
Для ё = 0 По Таблица1.Колонки.Количество() - 1 Цикл
ОбъединениеТаблиц.ЗагрузитьКолонку(Таблица1.ВыгрузитьКолонку(ё), ё)
КонецЦикла;
Колонок в таблицах значений обычно всегда значительно меньше, чем строк. Поэтому такой способ содержит меньше отдельных действий и в результате выполняется платформой быстрее построчного копирования. Ускорение зависит от соотношения числа строк и столбцов и может достигать полутора раз.
19. Загадка суммы и произведения
Пусть x и y два целых числа 1 < = x < = y притом x + y < = 100.
Салли сказали только сумму x + y, а вот Полю произведение xy.
Салли и Пол честнейшие ребята, это всем известно, они и друг другу отродясь не врали.
И вот такой вышел у них разговор:
Пол: «Не знаю я, что это за числа.»
Салли: «Тоже новость. Я знаю, что ты не знаешь.»
Пол: «Ну твоя то сумма мне теперь известна.»
Салли: «Да уж и мне теперь твое произведение.»
Каковы числа?
ВЫБРАТЬ 0 КАК Х
ПОМЕСТИТЬ Бит
ОБЪЕДИНИТЬ ВЫБРАТЬ 1
;
ВЫБРАТЬ Бит0.Х + 2 * (Бит1.Х + 2 * (Бит2.Х + 2 * (Бит3.Х + 2 * (Бит4.Х + 2 * (Бит5.Х + 2 * Бит6.Х))))) КАК Х
ПОМЕСТИТЬ Ряд
ИЗ Бит КАК Бит6, Бит КАК Бит5, Бит КАК Бит4, Бит КАК Бит3, Бит КАК Бит2, Бит КАК Бит1, Бит КАК Бит0
;
ВЫБРАТЬ Ряд1.Х КАК Х, Ряд2.Х КАК У, Ряд1.Х + Ряд2.Х КАК Сумма, Ряд1.Х * Ряд2.Х КАК ХУ
ПОМЕСТИТЬ Пробы
ИЗ Ряд КАК Ряд1, Ряд КАК Ряд2
ГДЕ 1 < Ряд1.Х И Ряд1.Х < Ряд2.Х И Ряд1.Х + Ряд2.Х <= 100
;
ВЫБРАТЬ РАЗЛИЧНЫЕ Сумма
ПОМЕСТИТЬ ТабуСумм
ИЗ Пробы
ГДЕ ХУ В (ВЫБРАТЬ ХУ ИЗ Пробы СГРУППИРОВАТЬ ПО ХУ ИМЕЮЩИЕ КОЛИЧЕСТВО(*) = 1)
;
ВЫБРАТЬ ХУ КАК Произведение
ПОМЕСТИТЬ ЧислаПоля
ИЗ Пробы
ГДЕ НЕ Сумма В (ВЫБРАТЬ * ИЗ ТабуСумм)
СГРУППИРОВАТЬ ПО ХУ
ИМЕЮЩИЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Сумма) = 1
;
ВЫБРАТЬ Сумма, МАКСИМУМ(Произведение), МАКСИМУМ(Х), МАКСИМУМ(У)
ИЗ Пробы ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЧислаПоля ПО ХУ = Произведение
ГДЕ НЕ Сумма В (ВЫБРАТЬ * ИЗ ТабуСумм)
СГРУППИРОВАТЬ ПО Сумма
ИМЕЮЩИЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Произведение) = 1
20. Поразрядное исключающее ИЛИ
Для решения задачи Задача о 64 монетах, двух заключённых и одной шахматной доске написан запрос
ВЫБРАТЬ
Дано.Икс
ПОМЕСТИТЬ Дано
ИЗ
&Дано КАК Дано
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
1 КАК Вес
ПОМЕСТИТЬ Позиции
ОБЪЕДИНИТЬ
ВЫБРАТЬ
2
ОБЪЕДИНИТЬ
ВЫБРАТЬ
4
ОБЪЕДИНИТЬ
ВЫБРАТЬ
8
ОБЪЕДИНИТЬ
ВЫБРАТЬ
16
ОБЪЕДИНИТЬ
ВЫБРАТЬ
32
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
СУММА(Разряды.Вес * (Разряды.Икс - (ВЫРАЗИТЬ(Разряды.Икс / 2 + 0.5 КАК ЧИСЛО(10, 0))) * 2 + 2)) КАК Икс
ИЗ
(ВЫБРАТЬ
Позиции.Вес КАК Вес,
СУММА((ВЫРАЗИТЬ(Дано.Икс / Позиции.Вес + 0.5 КАК ЧИСЛО(10, 0))) - 1) КАК Икс
ИЗ
Дано КАК Дано,
Позиции КАК Позиции
СГРУППИРОВАТЬ ПО
Позиции.Вес) КАК Разряды
Этот запрос определяет шесть разрядов контрольной суммы, полученных выполнением поразрядного суммирования по модулю два чисел, заданных в таблице "Дано". Приведенный запрос может использоваться при создании и проверке контрольных соотношений, при других действиях в арифметике полей Галуа GF(2^6). Запрос легко обобщается на другие разрядности.
21. Определение длины строки в запросе
Это тема из обсуждения "Как с помощью запроса посчитать количество символов в реквизите"
ВЫБРАТЬ
Дано.НомерСтроки,
Дано.Строка
ПОМЕСТИТЬ Дано
ИЗ
&Дано КАК Дано
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
0 КАК ё
ПОМЕСТИТЬ Р0
ОБЪЕДИНИТЬ
ВЫБРАТЬ
1
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
2 * Р1.ё + Р0.ё КАК ё
ПОМЕСТИТЬ Р10
ИЗ
Р0 КАК Р1,
Р0 КАК Р0
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
4 * Р32.ё + Р10.ё КАК ё
ПОМЕСТИТЬ Р3210
ИЗ
Р10 КАК Р32,
Р10 КАК Р10
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
16 * Р54.ё + Р3210.ё + 1 КАК ё
ПОМЕСТИТЬ Р543210
ИЗ
Р10 КАК Р54,
Р3210 КАК Р3210
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Дано.НомерСтроки,
Дано.Строка,
МАКСИМУМ(Р543210.ё) КАК ДлинаСтроки
ИЗ
Дано КАК Дано,
Р543210 КАК Р543210
ГДЕ
ПОДСТРОКА(Дано.Строка, Р543210.ё, 1) + "!" <> "!"
СГРУППИРОВАТЬ ПО
Дано.НомерСтроки,
Дано.Строка