Один способ я знаю. Интересует: есть ли другие способы?
---
Окончательно:

```1c
    РезультатВыборки = Новый Массив;

    ПервоначальнаяТаблица = Новый ТаблицаЗначений;
    ПервоначальнаяТаблица.Колонки.Добавить("Товар", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

    Для СчЭлементов = 1 По 2 * НадоСлЭлементов Цикл
    Номенклатура = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор());
    СслкаИД = Номенклатура.УникальныйИдентификатор(); // Нового().УникальныйИдентификатор();

    ПервоначальнаяТаблица.Добавить().Товар = Номенклатура;
    КонецЦикла;

    Запросо = Новый Запрос;
    Запросо.Текст = "ВЫБРАТЬ
    | НедействительныеСсылки.Товар КАК Товар
    |ПОМЕСТИТЬ Товары
    |ИЗ
    | &НедействительныеСсылки КАК НедействительныеСсылки
    |
    |ИНДЕКСИРОВАТЬ ПО
    | Товар
    |;
    |
    |////////////////////////////////////////////////////////////­////////////////////
    |ВЫБРАТЬ
    | МАКСИМУМ(ЕСТЬNULL(Номенклатура.Ссылка, ПервыйЭлемент.Ссылка)) КАК Номенклатура,
    | НедействительныеСсылки.Товар
    |ПОМЕСТИТЬ ВсякаБяка
    |ИЗ
    | Товары КАК НедействительныеСсылки
    | ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ ПЕРВЫЕ 1
    | Номенклатура.Ссылка КАК Ссылка
    | ИЗ
    | Справочник.Номенклатура КАК Номенклатура
    | ГДЕ
    | Номенклатура.ЭтоГруппа = ЛОЖЬ) КАК ПервыйЭлемент
    | ПО (ИСТИНА)
    | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
    | ПО НедействительныеСсылки.Товар >= Номенклатура.Ссылка
    | И (Номенклатура.ЭтоГруппа = ЛОЖЬ)
    |
    |СГРУППИРОВАТЬ ПО
    | НедействительныеСсылки.Товар
    |;
    |
    |////////////////////////////////////////////////////////////­////////////////////
    |ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ " + Формат(НадоСлЭлементов, "ЧГ=") + "
    | ВсякаБяка.Номенклатура
    |ИЗ
    | ВсякаБяка КАК ВсякаБяка";

    Запросо.УстановитьПараметр("НедействительныеСсылки",ПервоначальнаяТаблица);
    //Запросо.УстановитьПараметр("Массиво", РезультатВыборки);

    РезЗапроса = Запросо.Выполнить();
    Если Не РезЗапроса.Пустой() Тогда

    СлучайныеТовары.ЗагрузитьЗначения(РезЗапроса.Выгрузить().ВыгрузитьКолонку("Номенклатура"));
    СлучайныеТовары.СортироватьПоЗначению(НаправлениеСортировки.Возр);
    КонецЕсли;

    Сообщить(СлучайныеТовары.Количество());
```
---
ildarovich, есть
---
А Ваш способ опубликован где-то?
---
Да, конечно. Вопрос был задан для привлечения внимания вот к этой публикации: Расчет хэш-функции в запросе . (Пример 3).
---
И как определить принадлежность способа к категории "другие" при отсутствии знаний о категории "не другие"?
---
sssss_aaaaa_2011, наверняка автор имеет в виду получение с помощью ГенераторСлучайныхЧисел: пронумеровать все элементы справочника от 1 до КоличествоЭлементов, получить нужное количество случайных номеров в диапазоне от 1 до КоличествоЭлементов, получить нужные элементы по этим случайным номерам.
---
Lovish, нумерация элементов - очень трудоемкий этап. Трудоемкость растет квадратично по отношению к числу элементов справочника. Попробуйте для примера пронумеровать в запросе свой справочник номенклатуры или контрагентов - результата придется ждать очень долго.
---
sssss_aaaaa_2011, сойдет любой работающий В ЗАПРОСЕ способ. Свой способ я отличу.
---
ildarovich, спасибо, вы сделали мне большое одолжение озвучив таки хоть какие-то критерии оценки вариантов вашим величеством. :/
---
Для этого в базе и есть генератор случайных чисел...
---
Bienko, "в базе" генератора нет, к сожалению. В языке запросов, я имею ввиду нет, а решение нужно именно в запросе.
---
Нумерация элементов очень трудоемкий этап.Попробуйте для примера пронумеровать в запросе свой справочник номенклатуры или контрагентов.
---
```1c
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    | Контрагенты.Ссылка,
    | Контрагенты.Код
    |ИЗ
    | Справочник.Контрагенты КАК Контрагенты
    |ГДЕ
    | Контрагенты.Код ПОДОБНО &СлучайнаяСекунда";

    Запрос.УстановитьПараметр("СлучайнаяСекунда","%"+ Секунда(ТекущаяДата())+"%");
```
---
ZOMI, дык ровно через минуту запрос вернет тот же результат. Разве это случайность?
---
TMV, где в задаче было условие "каждую минуту запросом получать случайный набор элементов"? ))

Я привел пример с секундой - можно усложнить играясь с текущим временем если запросы будут периодическими
---
ZOMI, это почти то, что нужно, но есть подозрение, что некоторые коды при таком подходе будут иметь преимущество.
---
на инфостарте уже писали как случайное число сделать, в запрос параметр передать думаю не составит сложности

```1c
    //НВЮ/ Получение Случайного Числа
    //
    // Параметры
    // <Мин> - <Число> - Нижняя граница Равномерного Распределения
    // <Макс> - <Число> - Верхняя граница Равномерного Распределения
    //
    // Возвращаемое значение:
    // <Число> - Сгенерированное случайное число
    //
    Функция ПолучитьСлучайноеЧисло(Мин=0,Макс=100) Экспорт

    //вместо Randomize
    Для н = 1 По Макс Цикл
    Уник = Новый УникальныйИдентификатор;
    КонецЦикла;

    //генерируем GUID
    Уник = СокрЛП(Новый УникальныйИдентификатор);

    //оставляем только цифры
    Уник = СтрЗаменить(Уник,"-",");
    Уник = СтрЗаменить(Уник,Символы.НПП,");

    Случ = 0;
    //знаменатель должен иметь такую же разрядность
    Знаменатель = 1;
    Для н = 1 По (СтрДлина(Уник)) Цикл
    ТекС = Сред(Уник,н,1);
    Если ТекС="a" Тогда
    Случ = Случ + Знаменатель*10;
    ИначеЕсли ТекС="b" Тогда
    Случ = Случ + Знаменатель*11;
    ИначеЕсли ТекС="c" Тогда
    Случ = Случ + Знаменатель*12;
    ИначеЕсли ТекС="d" Тогда
    Случ = Случ + Знаменатель*13;
    ИначеЕсли ТекС="e" Тогда
    Случ = Случ + Знаменатель*14;
    ИначеЕсли ТекС="f" Тогда
    Случ = Случ + Знаменатель*15;
    ИначеЕсли ТекС="1" Тогда
    Случ = Случ + Знаменатель;
    ИначеЕсли ТекС="2" Тогда
    Случ = Случ + Знаменатель*2;
    ИначеЕсли ТекС="3" Тогда
    Случ = Случ + Знаменатель*3;
    ИначеЕсли ТекС="4" Тогда
    Случ = Случ + Знаменатель*4;
    ИначеЕсли ТекС="5" Тогда
    Случ = Случ + Знаменатель*5;
    ИначеЕсли ТекС="6" Тогда
    Случ = Случ + Знаменатель*6;
    ИначеЕсли ТекС="7" Тогда
    Случ = Случ + Знаменатель*7;
    ИначеЕсли ТекС="8" Тогда
    Случ = Случ + Знаменатель*8;
    ИначеЕсли ТекС="9" Тогда
    Случ = Случ + Знаменатель*9;
    КонецЕсли;
    Знаменатель = Знаменатель * 16;
    КонецЦикла;

    Случ = Случ / Знаменатель; //здесь получается дробное случайное число от 0 до 1

    //преобразуем его в случайное число из заданного интервала, округляем до целого
    ЧислоИзИнтервала = Мин(Макс(Окр(Мин + (Макс-Мин)*Случ),Мин),Макс);

    Возврат ЧислоИзИнтервала;

    КонецФункции //ПолучитьСлучайноеЧисло()
```
---
volga23rus, а чем так плох встроенный в 1С датчик случайных чисел, что надо было эту жуткую функцию писать?
---
ничем не плох, просто организатор обсуждения про один способ знает и просил что-нибудь аналогичное.
Думаю первый способ как раз и был: ГенераторСлучайныхЧисел
---
volga23rus, нет, датчик случайных чисел не подходит, так как его нельзя использовать внутри запроса.
---
в самом запросе случаное не получить, в любом случае, случайные числа нужно получать отдельно и передавать в запрос в виде параметров или в виде таблицы значений с числами. а там уже у кого как фантазия работает.
---
spezc, ну почему же - можно. Топикстартер стартанул таким тоном, что раскалываться не хотелось, но, видимо, что-то озвучить придётся :(
ГенераторСлучайныхЧисел не на волшебной пыльце работает, это обычные вычисления, которые можно проделать в запросе. Классический ГСЧ (дальше могу слегка напутать - последний раз занимался этим вопросом ещё в прошлом веке) это два нечётных (чтобы не накапливались нули в младших разрядах, что приведёт к вырождению ГСЧ) числа - seed и как_там_его_называют. Каждое обращение к ГСЧ происходит следующее:

```1c
    как_там_его_называют=(seed*как_там_его_называют) % 2^разрядность;
    Возврат как_там_его_называют;
```

Всего делов - передать в параметре запроса случайный seed, чтобы последовательные выполнения этого запроса приводили к разным результатам.
---
spezc, ты статьи ildarovich по запросам читал же? По-моему, он запросами скоро задачи из курса высшей математики начнет решать, к этому все идет :) Хотя... Эммм... Он уже их решает вроде...
---
spezc, тут я и хотел разнообразные фантазии увидеть. Даже если ввести таблицу случайных чисел или случайный параметр - что дальше со справочником делать? Тут уже предложили через "подобно" отбирать, но тогда некоторые коды могут иметь преимущество при выборе. А хотелось бы бОльшей случайности.
А возможно, кто-то и источник энтропии в запросе подскажет где взять. Если работа многопользовательская, то можно время последнего записанного документа использовать, но это крайне не надежно.
---
ildarovich, А возможно, кто-то и источник энтропии в запросе подскажет где взять

А просто передать в параметр значение одинэсовского ГСЧ чем плохо? Запрос всё-равно не в отдельной вселенной выполняется, туда по-любому можно параметр передать.
---
а если просто запрос типа "выбрать первые N ссылка из справочник.мойсправочник упорядочить по " а тут уже сортировку и направление случайным образом выбирать
---
https://msdn.microsoft.com/en-us/library/cc441928.aspx
---
Serginio, спасибо, отличная ссылка!!! Вот только в 1С не NewId не Rand нет.

Я еще на хабре видел похожее обсуждение Postgres. Выборка N случайных записей.
---
Ну если очень хочется, то прямой запрос в руки. Сам часто использую для объединения стороннх данных и регистра сведений через Merge. А там миллионы записей.
---
```1c
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    | Контрагенты.Ссылка
    |ИЗ
    | Справочник.Контрагенты КАК Контрагенты
    |ГДЕ
    | Контрагенты.ЭтоГруппа = ЛОЖЬ";

    Тз = Запрос.Выполнить().Выгрузить();

    Тз.Колонки.Добавить("Сортировка",Новый ОписаниеТипов("Число"));

    Для каждого строка из ТЗ цикл
    ГСЧ = Новый ГенераторСлучайныхЧисел;
    Строка.Сортировка= ГСЧ.СлучайноеЧисло(0, 4294967295);
    КонецЦикла;

    Запрос2 = Новый Запрос;
    Запрос2.Текст =
    "ВЫБРАТЬ
    | кТ.Ссылка,
    | кТ.Сортировка
    |ПОМЕСТИТЬ КТВ
    |ИЗ
    | &Кт КАК кТ
    |;
    |
    |////////////////////////////////////////////////////////////­////////////////////
    |ВЫБРАТЬ ПЕРВЫЕ 5
    | КТВ.Ссылка,
    | КТВ.Сортировка КАК Сортировка
    |ИЗ
    | КТВ КАК КТВ
    |
    |УПОРЯДОЧИТЬ ПО
    | Сортировка";

    Запрос2.УстановитьПараметр("Кт", Тз);
    рез= Запрос2.Выполнить().Выбрать();
    Пока рез.Следующий() цикл
    Сообщить(рез.ссылка);
    КонецЦикла;
```

2 запрос выбирает случайные элементы =)

п.с. просьба сильно не бить ))
---
Cool_vsi, а что, формально всё соблюдено. Как говорил Дядя Фёдор коту Матроскину: "Чтобы выбрать в запросе что-то случайное, надо сначала передать туда что-то случайное, а у нас в запросе ГСЧ нет".
---
Cool_vsi, это будет работать, но все же это не метод "в запросе".
Кроме того, если уж выбрали весь справочник в память, нужно сразу выбирать из него элементы генерацией пяти случайных чисел (проверив, что они различные). Это будет гораздо быстрее, чем для каждой строки получить случайное число (а если строк 10 тысяч?), а затем эту огромную таблицу перегонять в запрос.
Тут как раз и видна проблема: для того, чтобы выбрать всего пять элементов, приходится выбирать все элементы справочника.
---
ildarovich, я сам удивился но работает быстро, меньше секунды для 7000 элементов, формально исходя из название темы все условия соблюдены ..а реально да , это не 1 запрос..насчет выборки всех элементов, думаю если в запросе сделать несколько виртуальных таблиц,в которых будут все элементы то по скорости будет не намного быстрее...да сам хочу посмотреть на чистый запрос в 1с, который быстро случайно выберет n элементов...
---
все что можно написать из 1С (по моему мнению) - это проиндексировать выборку случайными значениями и потом выбрать N элементов с учетом сортировки - способ затратный получается.

Проще сделать прямой запрос к базе и получить в зависимости от вида SQL (NEWID()), Рostgree (Random()), db2(не помню, но тоже что то c RAND()) набор ID - в случае файловой остается чистый 1с например - выборка.Следующий и ГСЧ.

не универсально конечно.. но и ресурсы не резиновые - создания таблиц порождающими запросами да если еще и не в один поток - быстро загонит бд в ступор
---
caponid, для MSSQL и Postgre в комментариях (23) и (25) решения приведены. Видно, что с NewID() тоже не все так просто.

Порождающий запрос тут не собирался использовать, поэтому про "загонит БД в ступор" (в чем я сомневаюсь) спорить смысла нет.
---
ну сгенерируй случайное число сам, например использовав текущую дату и время....
---
poyson, а что с этим числом дальше делать? Ведь задача: выбрать случайные элементы из справочника в запросе. Как для этого случайное число дальше использовать? Нужен текст запроса наподобие (11).
---
на основе уникального идентификатора получать случайные числа
---
```1c
    ВЫБРАТЬ
    СотрудникиОрганизаций.Ссылка КАК НомерСтроки,
    ПОДСТРОКА(СотрудникиОрганизаций.Код, 0, 10) КАК Строка
    ПОМЕСТИТЬ Дано
    ИЗ
    Справочник.СотрудникиОрганизаций КАК СотрудникиОрганизаций
    ;

    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ 0 С, 1 КАК П
    ПОМЕСТИТЬ Р16
    ОБЪЕДИНИТЬ ВЫБРАТЬ 1, 10
    ОБЪЕДИНИТЬ ВЫБРАТЬ 2, 100
    ОБЪЕДИНИТЬ ВЫБРАТЬ 3, 1000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 4, 10000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 5, 100000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 6, 1000000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 7, 10000000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 8, 100000000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 9, 1000000000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 10, 10000000000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 11, 100000000000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 12, 1000000000000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 13, 10000000000000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 14, 100000000000000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 15, 1000000000000000
    ОБЪЕДИНИТЬ ВЫБРАТЬ 16, 10000000000000000;

    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    Дано.НомерСтроки,
    СУММА(А.П * Б.С * ВЫБОР
    КОГДА ПОДСТРОКА(Дано.Строка, 1, 17 - А.С) ПОДОБНО "%.%"
    ТОГДА 10
    ИНАЧЕ 1
    КОНЕЦ) / МИНИМУМ(ВЫБОР
    КОГДА НЕ ПОДСТРОКА(Дано.Строка, 1, 17 - А.С) ПОДОБНО "%.%"
    ТОГДА А.П
    ИНАЧЕ 100000000000000000
    КОНЕЦ) КАК Ответ
    ПОМЕСТИТЬ Результат
    ИЗ
    Дано КАК Дано,
    Р16 КАК А,
    Р16 КАК Б
    ГДЕ
    Б.С < 10
    И ПОДСТРОКА(Дано.Строка, 17 - А.С, 1) = ПОДСТРОКА("0123456789", Б.С + 1, 1)

    СГРУППИРОВАТЬ ПО
    Дано.НомерСтроки
    ;

    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ ПЕРВЫЕ 5
    Результат.НомерСтроки,
    Результат.Ответ,
    ((ВЫРАЗИТЬ(Результат.Ответ / &Сид КАК ЧИСЛО(10, 0)) - ВЫРАЗИТЬ(Результат.Ответ / &Сид КАК ЧИСЛО(10, 5)))) КАК Поле1
    ИЗ
    Результат КАК Результат

    УПОРЯДОЧИТЬ ПО
    Поле1
```

Использование остатка от деления на случайное число как сортировку
---
minimajack, я так понимаю что при сид=постоянное значению(попробовал разные варианты сид при одинаковых вариантах сид рез одинаков), то и выводиться будут тоже самое. Вариант 11 такойже только лаконичнее. Рандом число все-равно передается в запрос, и все пляшет от него.
---
Cool_vsi,
1 принцип разный
2 где написано что при одинаковом сиде должны быть разные результаты?
---
minimajack, общий принцип одинаковый, передаем случайное число получаем случайное, вариантов на самом деле очень много если передавать случайное число...я думаю всем интересен запрос, который сам будет генерировать случайный элементы без передачи в него случайных чисел, ваш вариант интересен с математической точки зрения...но с точки зрения скорости работы и принципа если есть вариант проще не стоит загоняться, ваш вариант проигрывает другим вариантом с прицыпом передачи в запрос случайного числа...
---
minimajack, хороший вариант. Его еще можно улучшить, если код-число преобразовывать по-другому. По формуле (А * Код + B) % 2^32, где A, B - некоторые "большие числа". Примеры "хороших" чисел можно посмотреть у Кнута. Например, А = 1664525, B = 0.
---
Если не передавать в запрос случайные значения, то можно только ориентироваться на какие-то изменения в базе. Например, как писалось выше на время создания, версию данных последнего документа или на количество каких-то записей. Но если с данными ничего не происходит, то вариантов нет.
---
hibico, вообще говоря, можно создать небольшую временную таблицу, где хранить номер итерации, увеличивая его при каждой следующей случайной выборке.
Но, конечно, хочется чего-либо типа времени, объема свободной памяти, всего, что может быть настоящим источником энтропии. ...блокировки?...
---
ildarovich, в доступных функциях запроса ничего не доступно, так что хоть тысячу раз запускай - ничего не изменится и во временных таблицах...причина этому - детерминированность алгоритмов - фактически это закон для компьютера. У нас не квантовые компьютеры - так что без внешнего источника энтропии - рыпаться бесполезно.
Если есть возможность сгенерировать до запроса, есть МенеджерКриптографии - там и парится не надо.
---
Расскажите хоть один способ без передачи параметра в запрос. Критерий случайности - не повторение выборки при одинаковой ИБ.
---
```1c
    ВЫБРАТЬ
    Контрагенты.Ссылка КАК Ссылка,
    Контрагенты.Код КАК Код,
    КОЛИЧЕСТВО(Контрагенты.Код) * 0 КАК Индекс
    ПОМЕСТИТЬ ВТ_ДАННЫЕ
    ИЗ
    Справочник.Контрагенты КАК Контрагенты
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагенты1
    ПО Контрагенты.Ссылка >= Контрагенты1.Ссылка

    СГРУППИРОВАТЬ ПО
    Контрагенты.Ссылка,
    Контрагенты.Код

    ИНДЕКСИРОВАТЬ ПО
    Индекс
    ;

    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ ПЕРВЫЕ 5
    ВТ_ДАННЫЕ.Ссылка,
    ВТ_ДАННЫЕ.Код,
    ВТ_ДАННЫЕ.Индекс
    ИЗ
    ВТ_ДАННЫЕ КАК ВТ_ДАННЫЕ

    УПОРЯДОЧИТЬ ПО
    ВТ_ДАННЫЕ.Индекс
```

Нашел!!! =))
Индексирование наше все )) для скульной базы работает
---
И чего ты нашел ?
И где тут случайность ?
Простейший примитив, как сделать нумерацию в тексте запроса.. не более того.
---
Ёпрст, проверил?
(47) как раз именно вариант с подзапросом с индексированием виртуального нуля дает случайную выборку
зы индексировать не обязательно =)
что бы не смущало

```1c
    КОЛИЧЕСТВО(Контрагенты.Код) * 0 КАК Индекс
```

заменить на

```1c
    КОЛИЧЕСТВО(0) * 0 КАК Индекс
```
---
Проверил. Выборка всегда одинаковая.
---
Ёпрст, странно у меня когда 4-5 через раз, то рандом(хотя некоторые элементы очень часто повторяются в отличии от других)то также...
---
я хз, че у тебя там за база, но на sql не будет рандома в этом случае, никогда
---
Ёпрст, у меня sql база, и когда выборка 4-5 значений выбираются разные при разных выполнениях
---
у меня тоже sql 2008 и результат всегда одинаковый.
---
Cool_vsi, у меня sql база, и когда выборка 4-5 значений выбираются разные при разных выполнениях
У меня sql 2008, выборка 5 элементов. Выборка повторяется в среднем через 3-4 итерации, иногда подряд идут. Но забавно, система не улавливается. )))
---
Ёпрст, любой рандом относительный...это же не криптография
поговорим у кого рандом у кого нет?
по условиям задачи все выполнено
---
С фигали выполнено, если не воспроизводится ?
И.. в (0) нет ни слова об использованиии СУБД.. для скуля, вообще проще rand() использовать и привет.
---
Ёпрст, согласен не всегда воспроизводится, на базе с > 5000 записей работает, на маленькой выборке результат один и тот же...жаль, видимо остается в кэше...
---
minimajack, проверил выбираем 4-5 боле менее рандом, выбираем 1000 уже не рандом....
---
И это, индексировать в этом запросе не обязательно
---
ну, разве что top 5 может иногда дать не тот вариант, если статистику обновить и все кеши сбросить
---
ВЫБРАТЬ ПЕРВЫЕ 3
---
а без генератора случайных чисел можно? и как быть если ты не попадешь в номер элемента?
---
reznic, а без генератора случайных чисел можно? можно, но тогда выборка не будет случайной, поэтому нельзя и как быть если ты не попадешь в номер элемента? а для этого случайное число надо нормировать. Типа вот так:
```1c
    НомерЭлемента=СлучайноеЧисло*КоличествоЭлементов/МаксимальноеСлучайноеЧисло
```
---
vasyak319,

```1c
    а для этого случайное число надо нормировать. Типа вот так:
```

огорчу...нормирование не поможет
либо перенумеровать случайные числа, либо случайное число получить из объекта(реквизита)
---
Выборка всегда одинаковая ?
---
Ну если передавать через параметр случайное число нельзя, тогда можно создать какой-то объект (или использовать существующий), например регистр сведений, и с какой-нибудь периодичностью заполнять его новым случайным числом (числами). А в запросе выбирать данный объект и на его основе делать выборку элементов.
---
А что если формировать результат запроса по курсам валют )
---
варианты привязки к коду номера элемента как к цифрам бред, не везде в коде есть цифры, или например еше есть буквы, или только буквы...пока считаю лучшим вариантом мой...абсолютный рандом =)
---
Cool_vsi, метод, приведенный в (26) слабо соответствует условиям задачи. Главное в условии - сделать выбор "в запросе". У вас же основные действия, а именно, добавление колонки со случайными числами, производятся вне запроса.

То есть последовательность у вас такова:
1) выбираем ВЕСЬ справочник в таблицу значений;
2) добавляем колонку и записываем в каждый элемент новой колонки случайное число;
3) возвращаем ВЕСЬ справочник с добавленной колонкой в запрос;
4) сортируем по рандомному столбцу;
5) отбираем первые 5.

Если убрать из вашего алгоритма явно избыточные (абсолютно лишние) действия, то должен остаться алгоритм:
1) выбираем ВЕСЬ справочник в таблицу значений;
2) выбираем с помощью ГСЧ из таблицы значений 5 разных элементов;
3) возвращаем выбранные случайные элементы в запрос.

то станет очевидным, где на самом деле делается случайный выбор.

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

С другой стороны, предложенный в (26) метод (с учетом поправок) очевиден и для практики совершенно нормален (единственно возможен?), если не задано условие "в запросе".
---
ildarovich, я не спорю что мой вариант не совсем подходит под условия задачи. Но варианты с передачей в запрос случайного числа и привязке к коду еще большее не подходят на мой взгляд.Самому интересно решение данного вопроса
---
как вариант... не нравится мне все таки идея с запросом в котором все...

```1c
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    | Номенклатура.Ссылка,
    | КОЛИЧЕСТВО(Номенклатура1.Код) КАК НомерСтроки
    |ИЗ
    | Справочник.Номенклатура КАК Номенклатура
    | ПОЛНОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура1
    | ПО (Номенклатура.Код >= Номенклатура1.Код)
    |
    |СГРУППИРОВАТЬ ПО
    | Номенклатура.Ссылка";

    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();

    Граница = Выборка.Количество();
    ГСЧ = Новый ГенераторСлучайныхЧисел(ТекущаяДата());

    КоличествоСлучайных = 5;
    сч = 1;

    ТЗ = Новый ТаблицаЗначений;
    ТЗ.Колонки.Добавить("Ссылка");

    Пока сч <= КоличествоСлучайных Цикл
    Индекс = ГСЧ.СлучайноеЧисло(1, Граница);
    Выборка.НайтиСледующий(Новый Структура("НомерСтроки",Индекс));
    НоваяСтрока = ТЗ.Добавить();
    НоваяСтрока.Ссылка = Выборка.Ссылка;
    сч = сч +1;
    КонецЦикла;
```
---
(75) caponid, совершенно лишняя нумерация справочника в запросе. Это тяжелая операция, которая требует соединения справочника с собой. Если разрешить себе выбор вне запроса (что не соответствует условию), то лучше делать так

```1c
    Запрос = Новый Запрос("ВЫБРАТЬ Ссылка, 0 КАК Отбор ИЗ Справочник.Номенклатура ГДЕ НЕ ЭтоГруппа");
    ВсеСсылки = Запрос.Выполнить().Выгрузить();
    ГСЧ = Новый ГенераторСлучайныхЧисел();
    Пока ВсеСсылки.Итог("Отбор") < 5 Цикл
    ВсеСсылки[ГСЧ.СлучайноеЧисло(0, ВсеСсылки.Количество() - 1)].Отбор = 1
    КонецЦикла;
    Запрос = Новый Запрос("ВЫБРАТЬ * ИЗ Справочник.Номенклатура ГДЕ Ссылка В (&ОтборныеСсылки)");
    Запрос.УстановитьПараметр("ОтборныеСсылки", ВсеСсылки.Скопировать(Новый Структура("Отбор", 1)));
    Запрос.Выполнить().Выгрузить().ВыбратьСтроку("Случайные элементы:")
```
Конечно, в практическом применении нужно учесть, что справочник может содержать менее 5 элементов и проверять зацикливание, ну и обеспечить выбор пяти РАЗЛИЧНЫХ ссылок вообще не через долгий подсчет, а через соответствие.
---
ildarovich,
"тяжелая операция соединения справочника с собой" - может быть и не так тяжела как выгрузка справочника в ТЗ. Надо сравнить в профайлере хотябы для SQL.
---
Какие вообще есть варианты?
В общем случае внутри запроса 1С получить случайное число невозможно (в частном случае, есть разные варианты – например, считать количество каких-либо постоянно добавляемых элементов справочника или смотреть какой-то объект в базе, куда мы постоянно специально будем записывать случайное число).
Следовательно, при выполнении запроса придётся каждый раз передавать случайное число (назову его Rand), т.е. при инициализации запроса одним и тем же случайным числом мы получим одни и те же "случайные" данные.
Итак, мы передали в запрос случайное число, что дальше?
Чтобы решение было универсальным мы можем привязаться только к стандартным реквизитам (других в справочнике просто может и не быть).
Из стандартных реквизитов подходит нам всего два - это уникальный "код" и относительно случайное "наименование". (С "ссылкой" мы никаких операций в запросе не сможем провести, поэтому она не подходит. Остальные реквизиты не обеспечивают практически никакой случайности, хотя если добавить и их, то случайность как минимум не понизится, но это замедлит процесс вычисления.)
Какой бы путь мы не выбрали нам всё равно придётся генерировать некий ключ на основе реквизитов "код" и "наименование" (в документах была бы ещё и "дата"). И ключ этот должен быть числовой, чтобы далее взаимодействовать с Rand.
Алгоритм вычисления ключа: Допустим и "наименование" и "код" имеют тип "строка". Чтобы обеспечить перевод строк в числа, нам понадобится временная таблица кодировки символов (с полями "Символ" и "Число") и функция "ПОДСТРОКА". Таким образом, выбирая символ, мы сразу сопоставляем ему число. Ну а далее из этих чисел по какой-нибудь хитрой формуле считаем ключ. Например, перемножаем все числа между собой (что-то у меня фантазия ещё не разогрелась).
Имея у каждого элемента справочника уникальный числовой ключ и случайное число, которым мы инициализировали запрос, выбрать случайные несколько элементов уже проще. Например, считаем поле «Порядок» как остаток от деления «ключа» на «Rand» (с помощью функции «Выразить»). Далее упорядочиваем по полю «Порядок» и выбираем первые N.
---
Патриот, ссылка тоже псевдо уникальная - гуиды то пакетами (вроде 20 на сессию) выдаются по возрастанию...
---
caponid, я писал, что С "ссылкой" мы никаких операций в запросе не сможем провести, поэтому она не подходит
---
Патриот, все логично, примерно так у меня и сделано. Я, в общем-то, задал вопрос для проверки: не пропустил ли я какой-либо более простой вариант решения этой задачи или нет ли какой свежей идеи. Ссылку на свое решение специально не привел, чтобы не затормозить приток идей.
Для меня обсуждение оказалось полезным по нескольким причинам:
- в комментарии (11) предложена свежая идея использование оператора "ПОДОБНО". Если бы можно обеспечить "ортогональность" сравнения через "ПОДОБНО" кодов справочника с несколькими базисными строками (чтобы результат сравнения делил справочник примерно пополам и для каждой базисной строки деление было бы независимым), то можно было бы развить этот подход;
- в комментарии (23) приведена полезная ссылка, которая напомнила, как можно ускорить решение, сократив затраты на сортировку. В результате смог еще ускорить свое решение;
- в комментарии (45) приведена одна из возможностей нахождения источника энтропии в запросе (правда, не надежная) и остается небольшая надежда, что, вдруг, есть и другие.
---
Давно наблюдаю за темой.. прочитал последний топик, где вопрос возникает как взять некое число рандом..
А если рассмотреть в запросе РазностьДат? Т.е. Некая константа.. Дата регистрации организации и текущая дата.
---
anterehin,
1. отнимая от текущей даты константу случайность не повысится, т.е. легче просто взять текущую дату.
2. текущую дату надо в запрос передать, т.к. внутри её не вычислить.
3. "Дата регистрации организации" скорее всего есть не в каждой базе, т.е. это ограничивает универсальность
---
или вот еще вариант

```1c
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    | КОЛИЧЕСТВО(Номенклатура.Ссылка) КАК ИндексВыборки
    |ИЗ
    | Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    | НЕ Номенклатура.ЭтоГруппа";
    ТЗ = Запрос.Выполнить().Выгрузить();

    Граница = ТЗ[0].ИндексВыборки;
    ТЗ.Очистить();
    ГСЧ = Новый ГенераторСлучайныхЧисел(ТекущаяДата());

    КоличествоСлучайных = 5;
    сч = 1;

    Пока сч <= КоличествоСлучайных Цикл
    Индекс = ГСЧ.СлучайноеЧисло(0, Граница);
    НоваяСтрока = ТЗ.Добавить();
    НоваяСтрока.ИндексВыборки = Индекс;
    сч = сч +1;
    КонецЦикла;

    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    | ВнешняяТаблица.ИндексВыборки
    |ПОМЕСТИТЬ ВТВыборки
    |ИЗ
    | &ТЗ КАК ВнешняяТаблица
    |;
    |
    |////////////////////////////////////////////////////////////­////////////////////
    |ВЫБРАТЬ
    | Номенклатура.Ссылка,
    | КОЛИЧЕСТВО(Номенклатура1.Код) КАК НомерСтроки
    |ПОМЕСТИТЬ ВТДанные
    |ИЗ
    | Справочник.Номенклатура КАК Номенклатура
    | ПОЛНОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура1
    | ПО Номенклатура.Код >= Номенклатура1.Код
    |ГДЕ
    | НЕ Номенклатура.ЭтоГруппа
    |
    |СГРУППИРОВАТЬ ПО
    | Номенклатура.Ссылка
    |;
    |
    |////////////////////////////////////////////////////////////­////////////////////
    |ВЫБРАТЬ
    | ВТДанные.Ссылка
    |ИЗ
    | ВТВыборки КАК ВТВыборки
    | ЛЕВОЕ СОЕДИНЕНИЕ ВТДанные КАК ВТДанные
    | ПО ВТВыборки.ИндексВыборки = ВТДанные.НомерСтроки";

    Запрос.УстановитьПараметр("ТЗ", ТЗ);

    ТЗ = Запрос.Выполнить().Выгрузить();
```
---
Тут видется только использование времени в качестве псевдослучайного элемента.
---
Deveruchi, какая разница, что использовать, если это надо передавать параметром в запрос?
Все еще считаю, что нет способов.
---
Я сделал-бы что-то вроде:

```1c
    Запрос = Новый Запрос;
    Запрос.Текст = "Выбрать Спр.Ссылка ИЗ Справочник.Контрагенты ГДЕ ..."; // Условие не пишу. Любое, которое нужно
    Выборка = Запрос.Выполнить.Выбрать();

    МассивСлучайныхЧисел = ПолучитьМассивСлучайныхЧисел();
    // Функция "ПолучитьМассивСлучайныхЧисел()" должна возвращать массив случайных чисел
    // от 0 (включая) до 1 (не включая) в нужном для задачи количестве.
    // Как сгенерировать случайное число - обсуждать не хочу, в этой ветке предложено много хороших вариантов,
    // кроме того в интернете очень много алгоритмов на эту тему.

    Для каждого СлучайноеЧисло из МассивСлучайныхЧисел Цикл
    СлучайнаяСсылка = Выборка.Получить( Цел( СлучайноеЧисло * Выборка.Количество() ) );
    Сообщить( Строка( СлучайнаяСсылка ) );
    КонецЦикла;
```

В результате всё решается в один запрос, без промежуточных таблиц и без анализа значений реквизитов справочника (в конце концов, разработчик может установить для кода или для наименования нулевую длину, и тогда просто нечего будет анализировать).
---
прямой скульный запрос вида SEL ECT * FR OM spravochnik WHERE Uslovine=5 ORDER BY rand() LIMIT 10
---
```1c
    РезультатВыборки = Новый Массив;

    Для СчЭлементов = 1 По НадоСлЭлементов Цикл
    Номенклатура = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор());
    СслкаИД = Номенклатура.УникальныйИдентификатор(); // Нового().УникальныйИдентификатор();

    Запросо = Новый Запрос;
    Запросо.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
    | ЕСТЬNULL(Номенклатура.Ссылка, ПервыйЭлемент.Ссылка) КАК Номенклатура
    |ИЗ
    | Справочник.Номенклатура КАК Номенклатура
    | ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ ПЕРВЫЕ 1
    | Номенклатура.Ссылка КАК Ссылка
    | ИЗ
    | Справочник.Номенклатура КАК Номенклатура
    | ГДЕ
    | Номенклатура.ЭтоГруппа = ЛОЖЬ) КАК ПервыйЭлемент
    | ПО (ИСТИНА)
    |ГДЕ
    | Номенклатура.Ссылка >= &Ссылка
    | И НЕ Номенклатура.Ссылка В (&Массиво)
    | И Номенклатура.ЭтоГруппа = ЛОЖЬ";

    Запросо.УстановитьПараметр("Ссылка", Номенклатура);
    Запросо.УстановитьПараметр("Массиво", РезультатВыборки);

    РезЗапроса = Запросо.Выполнить();
    Если Не РезЗапроса.Пустой() Тогда

    Номенклатура = РезЗапроса.Выгрузить()[0].Номенклатура;
    РезультатВыборки.Добавить(Номенклатура);
    КонецЕсли;
    КонецЦикла;

    СлучайныеТовары.ЗагрузитьЗначения(РезультатВыборки);
    СлучайныеТовары.СортироватьПоЗначению(НаправлениеСортировки.Возр);
```

Кажется, что первый элемент будет часто попадаться - но это лишь дыра в воображении. И тесты и разброс GUID-ов показывают, что все очень равномерно. Могут возникнуть трудности с количеством элементов сравнимым с мощностью справочника (быстродействие) - серия последовательных запросов ведет себя медленнее одного запроса сразу с таблицей внутри,
который можно сделать следуя данной методике: нагенерировав гуидов, представив их ссылками на справочник, запихнув в таблицу и связав со справочником выбирая максимум по существующим ссылкам в группировках по придуманным.
Сейчас попробую :)
---
```1c
    РезультатВыборки = Новый Массив;

    ПервоначальнаяТаблица = Новый ТаблицаЗначений;
    ПервоначальнаяТаблица.Колонки.Добавить("Товар", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

    Для СчЭлементов = 1 По НадоСлЭлементов Цикл
    Номенклатура = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор());
    СслкаИД = Номенклатура.УникальныйИдентификатор(); // Нового().УникальныйИдентификатор();

    ПервоначальнаяТаблица.Добавить().Товар = Номенклатура;
    КонецЦикла;

    Запросо = Новый Запрос;
    Запросо.Текст = "ВЫБРАТЬ
    | НедействительныеСсылки.Товар КАК Товар
    |ПОМЕСТИТЬ Товары
    |ИЗ
    | &НедействительныеСсылки КАК НедействительныеСсылки
    |
    |ИНДЕКСИРОВАТЬ ПО
    | Товар
    |;
    |
    |////////////////////////////////////////////////////////////­////////////////////
    |ВЫБРАТЬ
    | МАКСИМУМ(ЕСТЬNULL(Номенклатура.Ссылка, ПервыйЭлемент.Ссылка)) КАК Номенклатура,
    | НедействительныеСсылки.Товар
    |ИЗ
    | Товары КАК НедействительныеСсылки
    | ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ ПЕРВЫЕ 1
    | Номенклатура.Ссылка КАК Ссылка
    | ИЗ
    | Справочник.Номенклатура КАК Номенклатура
    | ГДЕ
    | Номенклатура.ЭтоГруппа = ЛОЖЬ) КАК ПервыйЭлемент
    | ПО (ИСТИНА)
    | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
    | ПО НедействительныеСсылки.Товар >= Номенклатура.Ссылка
    | И (Номенклатура.ЭтоГруппа = ЛОЖЬ)
    |
    |СГРУППИРОВАТЬ ПО
    | НедействительныеСсылки.Товар";

    Запросо.УстановитьПараметр("НедействительныеСсылки",ПервоначальнаяТаблица);
    //Запросо.УстановитьПараметр("Массиво", РезультатВыборки);

    РезЗапроса = Запросо.Выполнить();
    Если Не РезЗапроса.Пустой() Тогда

    СлучайныеТовары.ЗагрузитьЗначения(РезЗапроса.Выгрузить().ВыгрузитьКолонку("Номенклатура"));
    СлучайныеТовары.СортироватьПоЗначению(НаправлениеСортировки.Возр);
    КонецЕсли;
```

700 товаров менее чем за 2 секунды, есть повторения, но не первого элемента,
можно задавать 1300 товаров, сворачивать и 700 обрезать.
... результат в таблице, ВЫБРАТЬ РАЗЛИЧНЫЕ ... и
Файловая база 13 секунд 1300 неуникальных, 878 уникальных.
---
Окончательно:

```1c
    РезультатВыборки = Новый Массив;

    ПервоначальнаяТаблица = Новый ТаблицаЗначений;
    ПервоначальнаяТаблица.Колонки.Добавить("Товар", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

    Для СчЭлементов = 1 По 2 * НадоСлЭлементов Цикл
    Номенклатура = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор());
    СслкаИД = Номенклатура.УникальныйИдентификатор(); // Нового().УникальныйИдентификатор();

    ПервоначальнаяТаблица.Добавить().Товар = Номенклатура;
    КонецЦикла;

    Запросо = Новый Запрос;
    Запросо.Текст = "ВЫБРАТЬ
    | НедействительныеСсылки.Товар КАК Товар
    |ПОМЕСТИТЬ Товары
    |ИЗ
    | &НедействительныеСсылки КАК НедействительныеСсылки
    |
    |ИНДЕКСИРОВАТЬ ПО
    | Товар
    |;
    |
    |////////////////////////////////////////////////////////////­////////////////////
    |ВЫБРАТЬ
    | МАКСИМУМ(ЕСТЬNULL(Номенклатура.Ссылка, ПервыйЭлемент.Ссылка)) КАК Номенклатура,
    | НедействительныеСсылки.Товар
    |ПОМЕСТИТЬ ВсякаБяка
    |ИЗ
    | Товары КАК НедействительныеСсылки
    | ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ ПЕРВЫЕ 1
    | Номенклатура.Ссылка КАК Ссылка
    | ИЗ
    | Справочник.Номенклатура КАК Номенклатура
    | ГДЕ
    | Номенклатура.ЭтоГруппа = ЛОЖЬ) КАК ПервыйЭлемент
    | ПО (ИСТИНА)
    | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
    | ПО НедействительныеСсылки.Товар >= Номенклатура.Ссылка
    | И (Номенклатура.ЭтоГруппа = ЛОЖЬ)
    |
    |СГРУППИРОВАТЬ ПО
    | НедействительныеСсылки.Товар
    |;
    |
    |////////////////////////////////////////////////////////////­////////////////////
    |ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ " + Формат(НадоСлЭлементов, "ЧГ=") + "
    | ВсякаБяка.Номенклатура
    |ИЗ
    | ВсякаБяка КАК ВсякаБяка";

    Запросо.УстановитьПараметр("НедействительныеСсылки",ПервоначальнаяТаблица);
    //Запросо.УстановитьПараметр("Массиво", РезультатВыборки);

    РезЗапроса = Запросо.Выполнить();
    Если Не РезЗапроса.Пустой() Тогда

    СлучайныеТовары.ЗагрузитьЗначения(РезЗапроса.Выгрузить().ВыгрузитьКолонку("Номенклатура"));
    СлучайныеТовары.СортироватьПоЗначению(НаправлениеСортировки.Возр);
    КонецЕсли;

    Сообщить(СлучайныеТовары.Количество());
```
---
vugluscr1991, - отлично!
Нужно сказать, что такой способ я не стал пробовать из-за того, что запрос, в котором было "УПОРЯДОЧИТЬ ПО Ссылка" вернул мне явно не случайный порядок. Теперь думаю, что если сформировать справочник, генерируя ему уникальные идентификаторы подобным образом, то порядок был бы случайным. Нужно будет проверить.
Получается, что 2 (13) секунды 700 случайных элементов (пусть с повторением). А сколько всего элементов было в справочнике?
---
ildarovich,
2902 элемента, база файловая, виртуалка
---
vugluscr1991, не очень быстро для такого объема справочника. Улучшенный вариант того запроса, что описан в примере 3 в статье "Расчет хэш-функции в запросе" выдает 700 случайных элементов из справочника 15000 элементов примерно за 0,5 секунды.
Так что, если тщательно протестировать ваш метод на предмет равномерности распределения и там все будет хорошо, то его область применения - малые выборки.
---
ildarovich,
03.04.2015 20:31:14
                            Новый Запрос;
                            Выполнить();
03.04.2015 20:31:31
113 579 элементов в справочнике
700 случайных
Средне настроенный MS SQL на серверной платформе (аппаратное железо)
Дальнейшие тесты на платформе (умножение на 2 для случайных ссылок исключено из алгоритма 700 берем и количество уникальных смотрим):
200 000 элементов: 17 секунд 674 уникальных
66 000 элементов: 8 секунд 630 уникальных
9 000 элементов: 2 секунды 568 уникальных
1 000 элементов: менее секунды 77 уникальных
---
vugluscr1991, спасибо за результаты. Вообще метод мне понравился тем, что для выбора одного (или нескольких) элемента он очень быстр. Но при более глубоких размышлениях обнаружил в нем серьезный "математический" дефект - он никак не обеспечивает равной вероятности выбора различных элементов справочника.
Дело в том, что вероятность выбора одного элемента будет пропорционально расстоянию до следующего элемента (если представить ссылку как большое целое число, задающее положение элемента на числовой оси). Это расстояние складывается случайным образом при формировании идентификаторов элементов справочника, но остается фиксированным при наших выборках. И может быть очень разным для разных пар соседних элементов. Если сразу за конкретным элементом расположен следующий, а после него - большое расстояние, то этот первый элемент имеет очень мало шансов быть выбранным. И если распределение сгенерированных случайно ссылок на числовой оси более - менее равномерно, то вот расстояние между соседними элементами распределено неравномерно (кажется, по закону Пуассона или близкому к нему). Так что добиться равновероятности, не распределяя ссылки равномерно (что мы сделать не можем), не получится. Поэтому правильный алгоритм, видимо, вынужден быть линейным по времени - предусматривать обработку каждой ссылки. Или опираться на готовую сплошную нумерацию элементов.
Как-то так.
---
ildarovich,
думаю, что все не так опасно, как кажется на первый взгляд. Я задумывался об этом при построении решения и вероятность того, что элементы окажутся "рядом" - также крайне мала. Неравномерность распределения обусловлена неравномерностью сгенерированых ГУИДов, а они друг от друга отстоят на расстояния несравнимые с количеством элементов даже в миллионных справочниках.
Это по началу в платформе 1С были трудности, связанные с индексированием ГУИДов и справочники заполненные скажем в 1С версии 8.0 (я точные номера версий не знаю) будут иметь ГУИДы из системы (хорошие и очень далекие друг от друга), потом (пусть "условно" в 8.1) 1С изменили поведение генерации ГУИДов, сделав их похожими друг на друга и расположив очень близко (у меня есть такие справочники, заполненные так, что на 120 000 элементов в выборке 700 различных было всего 77 попутал, 77 различных было на справочнике в 752 элемента) я не уверен на все 100%, но в таких справочников ГУИД элемента делали из ГУИДа типа + максимум + 1 и индексироваться такие справочники стали веселей, но выглядели слишком грустно с точки зрения уникальности (тут, кстати, можно и конспирологию включить, на тему того, что заказчики хотели однозначной идентификации компьютера и ОС создавшей любой элемент любого справочника, или хотябы отсутствие повторов в принципе) и вот по результатам наблюдений я не вижу в 8.2 и в 8.3 общих частей у сгенерированных ГУИДов - похоже они (1С) решили проблнму индексации таких чисел и вернулись к системным ГУИДам, которые в свою очередь имеют прекрасное распределение (лучше чем многие "ГСЧ на коленке").
---
vugluscr1991, это я понимаю. Это технологические моменты. Я говорю уже о другом. Пусть ГУИДы идеальные. Они будут распределены равномерно. Но случайно! Между ними не будет одинакового расстояния! Оно будет тоже случайным и разным. Напимер, есть пять водителей (см.рисунок). Вместо ГУИД возьмем настоящее случайное число от 0 до 1 (функция СЛЧИС() EXCEL). Получается расстояние от ГУИДа водителя Бухарикова до ГУИДа Подкаблучникова таково, что первого будут проверять в ДВА РАЗА реже, чем второго, если для проверки перед рейсом выбирать водителя вашим методом. Если вы думаете, что когда водителей будет 200000 ситуация изменится - это не так. Расстояния будут микроскопические, но под микроскопом такими же разными. И вероятность проверки самого "везучего" по сравнению с самым "невезучим" будет еще сильнее отличаться.
---
ildarovich,
это именно так в теории вероятности, которая работает в предположениях закона больших чисел. А рабочими условиями закона больших чисел является не только мощность пространства событий (первое большое число), но и количество испытаний (практика, второе большое число). Я пишу о том, что в случае большого количества испытаний - Вы правы на все 100% будут "невезучие" водители, расположенные слишком близко к везучим. Но провести такое количество испытаний (мое предположение) Вы не в силах, если не будете создавать для этого специальную испытательную программу и подключать к этому вычислительные мощности. Ваши практические выборки имеют малое число испытаний (даже если это миллионы, ибо ГУИДы по разрядности значительно больше), поэтому элемент случайности на таких выборках реализован максимально.
Если же делать выборки в количестве годном к тому, чтобы считать его большим числом, тогда можно будет доказать "невезучесть" определенных водителей, но лишь в этих непрактических лабораторных условиях.
И вообще, на мой взгляд, если выборка равномерно закрывает пространство событий - то это повод для критики её случайности с философских позиций: глядя на процесс испытаний и зная, что ГСЧ идеален мы начинаем предсказывать заполнение пустых областей пространства событий результатами испытаний, а в идеально случайном процессе должен отсутствовать всякий детерминизм. Это означает, что кроме источника энтропии, должен быть также большой запас неопределенности. Что мы и имеем в результате малого количества испытаний в пространстве ГУИДов.
---
vugluscr1991, конечно, в этом вопросе есть элемент "философии".
Но, прежде чем рассуждать философски, отмечу несколько фактических ошибок в ваших рассуждениях:
1) "Большое" количество испытаний при которым становится заметной неравномерность распределения, на самом деле не такое уж и большое. Оно никак не связано с разрядностью ГУИДов. А только с количеством элементов справочника. Например, для приведенного примера за год не должно встретится ни одного месяца, когда Подкаблучникова проверяли реже чем Бухарикова. Это означает, что мы просто зря тратили ресурсы на слишком частую проверку одного и того же человека (искали под фонарем). Это конкретные экономические потери. То есть порядок числа испытаний, при котором проявляется неравномерность - тот же, что и число элементов справочника.
Не знаю, какой формулой это доказать. Хотя ... , например: сколько нужно испытаний, чтобы с вероятностью больше 50% (другая цифра) хотя бы раз был выбран каждый элемент справочника. а) при методе, обеспечивающим равную вероятность выбора; б) при выборе отрезка между случайными ГУИДами. Формула будет зависеть только от числа элементов справочника и должна показать колоссальную разницу этих чисел. (чуть позже приведу)
2) А вот это просто заблуждение (распространенное)выборка равномерно закрывает пространство событий - то это повод для критики её случайности с философских позиций: глядя на процесс испытаний и зная, что ГСЧ идеален мы начинаем предсказывать заполнение пустых областей пространства событий результатами испытаний, а в идеально случайном процессе должен отсутствовать всякий детерминизм. Это означает, что кроме источника энтропии, должен быть также большой запас неопределенностиЛюди, знающие теорию вероятностей, знают, что при независимости испытаний то, что монетка 20 раз подряд выпадет одной стороной, не означает, что это изменит ее вероятность выпасть той же стороной в следующем испытании. Они не начинают так предсказывать. Следующий результат с независимой вероятностью попадет в пустую или занятую область. Это - азбука! Энтропия и неопределенность - синонимы.

Собственно, жестко спорить я не хочу. Метод имеет право на жизнь. Нужно только отчетливо представлять его недостатки. Кстати, при большом желании неравномерность распределения ведь можно и скорректировать, выбирая элементы "с запасом" и дополнительно отбирая их потом случайным образом с вероятностью, обратно пропорциональной (? - нужно еще уточнить) размеру отрезка между ГУИДами. Проблема только в определении величины этого запаса. Поэтому все же лучше будет выбирать по одному.
---
ildarovich,
что монетка 20 раз подряд выпадет одной стороной ...
да заблуждение распространенное, но именно такого я не писал, я писал о практической разности энтропии (как характеристики исходных данных для испытаний) с неопределенностью испытаний, которые должны произойти в будущем до получения их большого числа.
"20 раз подряд орел" - это не заблуждение, а оговорка (исходя из контекста высказывания), когда не верно говорят о вероятности следующей решки, оперируя при этом понятием математическим "вероятность" и имея в виду ожидание (не математическое, а азартно-практическое) этого исхода (решки). Даже профессиональные математики путают термины и контексты, чего же мы хотим от людей не имеющих в активном аппарате точных определений.
Я тоже пишу не с целью спорить, просто делюсь своим видением случайности: если Бухарикова не будут проверять из-за короткого интервала между ГУИДами - это и есть случайность, а если идеальный ГСП равномерно закрасит нам квадрат (1,1) - это предопределено.
---
vugluscr1991, спасибо, теперь я лучше понял вашу мысль. Кажется, вы считаете, что выбор будет более случайным (по настоящему случайным), если мы сначала случайно выберем закон распределения, а потом, в соответствии с этим случайным законом - само случайное число. Не согласен с этим. В теории информации есть четкая количественная мера случайности (неопределенности, энтропии) - это Сумма(Pj*log(Pj)). Она максимальна при равной вероятности исходов P1 = P2 = ... = Pn. И никакое дополнительное услучайнивание здесь не поможет.

С чем я соглашусь, так это с тем, что для конкретной одной проверки можно выбирать объект хоть считая число согласных в его фамилии, хоть число лепестков на ромашке.
Но как только вы встроете этот механизм в тиражное решение, которым пользуются тысячи предприятий, тут и проявится методологическая ошибка метода. У вас на выявление одного нетрезвого водителя будет уходить 1000 рублей, к примеру. А у конкурентов, пользующихся в своем программном продукте правильной (научно обоснованной) стратегией - 500. Разница есть.

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

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