Выбор 10 элементов на основе N числовых типов

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

Поэтому, если пользователь выбирает type 1, программа должна выбрать 10 items из type 1

если пользователь выбирает type 1 and 2, программа должна выбрать 5 items из type 1 и 5 items из type 2

если пользователь выбирает type 1 , 2 and 4, программа должна выбрать 3 items для each type и один из типов должен иметь и extra item, чтобы получить 10 элементов, и какой тип получает дополнительный вопрос, должен быть случайным.

Таким образом, это необходимо сделать для N типов, из которых пользователь может выбирать.

Есть какие-нибудь предложения о том, как этого можно достичь?

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

Ps: Я кодирую на python, но любой языковой код подойдет.

PS: Я уже могу выбирать элементы с помощью предложения SQL WHERE, это не настоящая проблема.

проблема в том, что как только я получил элементы каждого из выбранных типов, мне нужно выбрать ровно 10 элементов с указанными выше пропорциями, (т.е.): если выбрано 4 типа, 2 элемента для каждого типа и ровно 2 дополнительных элемента в любых двух типов.


person Gautam    schedule 25.10.2011    source источник
comment
Что у тебя так далеко? Stack Overflow - хорошее место для советов и идей по homework и этому типу вопросов в целом, при условии, что вы показываете, что пытались решить проблему самостоятельно ...   -  person mjv    schedule 25.10.2011
comment
Можем ли мы предположить, что вы используете реляционную базу данных?   -  person Brendan Long    schedule 25.10.2011
comment
@mjv: Я пытался решить это с помощью операторов if, как вы могли догадаться, это было не очень красиво, кстати, это не совсем домашняя работа   -  person Gautam    schedule 25.10.2011
comment
@BrendanLong Ya. Я использую сейчас sqlite, но я перейду на mysql или Posgresql   -  person Gautam    schedule 25.10.2011
comment
@BrendanLong: Это личный проект, который я строю дома. Так что не совсем домашняя работа.   -  person Gautam    schedule 25.10.2011


Ответы (3)


Один из способов - просканировать БД за один проход, создав десять выбранных вами вариантов. Вот какой-то псевдокод:

  • Запросить во всей базе данных записи, соответствующие критериям пользователя.
  • Составьте первые десять, встречающиеся в списке результатов.
  • Если возникают какие-либо дополнительные записи, случайным образом решите, включать ли их (n-й элемент должен быть включен с вероятностью P (10 / n)): if random() < 10.0 / n: ...
  • Если он должен быть включен, случайным образом выберите предыдущий выбор для замены: i = randrange(10)

В Python:

result = []
for n, row in enumerate(cursor.execute(user_query), 1):
    if n <= 10:
        result.append(row)
    elif random() < 10.0 / n:
        i = randrange(10)
        result[i] = row

В качестве альтернативы, если база данных не запрашивается, огромна и имеет высокий процент записей, которые, как ожидается, будут соответствовать критериям пользователя, вы можете случайным образом выбрать записи из всей БД, пока не найдете десять уникальных записей, соответствующих критериям:

result = set()
while len(result) < 10:
     record = random.choice(entire_db)
     if record not in result and matches(record, user_criteria):
          result.add(record)

Последний алгоритм - один из двух, используемых собственной функцией Python random.sample ().

Если вы можете запускать запросы и количество совпадающих записей может поместиться в памяти, все сводится к следующему:

random.sample(list(cursor.execute(user_query)), 10)
person Raymond Hettinger    schedule 25.10.2011
comment
Вы потеряли меня в цикле по всей базе данных. Звучит невероятно неэффективно. - person Brendan Long; 25.10.2011
comment
Первые два шага сводятся к следующему: SELECT * FROM some_table WHERE some_user_criteria. Вы должны как-то идентифицировать свою популяцию. - person Raymond Hettinger; 25.10.2011

В основном вам нужно получить это в такой форме:

SELECT item
FROM items
WHERE type = ...
ORDER BY RANDOM()
LIMIT 10

См. Выбрать случайное значение из таблицы SQLite. Это должно работать и для PostgreSQL.

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

Для нескольких я бы, вероятно, просто запустил несколько запросов или динамически сгенерировал один с несколькими объединениями.

Сделать это можно так:

SELECT item
FROM items
WHERE type = type1
ORDER BY RANDOM()
LIMIT 5
UNION ALL
SELECT item
FROM items
WHERE type = type2
ORDER BY RANDOM()
LIMIT 5

Что может быть сгенерировано Python следующим образом:

types = ("type1", "type2", "type3")
limit = 10 // len(types) # be careful, for 11 or more types, this will set the limit to 0
sql = """
    SELECT item
    FROM items
    WHERE type = ?
    ORDER BY RANDOM()
    LIMIT %s
""" % (limit)
unioned_sql = " UNION ALL ".join([sql for i in range(len(types))])
result = cursor.execute(unioned_sql, types)

Синтаксис может быть неправильным - я давно не использовал DB API. Однако это должно дать представление.

Вы упомянули, что проблема заключается в том, что вам нужно выбрать ровно 10 элементов, включая дополнительные, если пропорция не работает ровно до 10, поэтому, возможно, было бы лучше жестко указать ограничение на 10 (выберите до 100 элементов) , а затем обрезать список после получения его из БД.

person Brendan Long    schedule 25.10.2011

Некоторые вещи могут оказаться полезными:


Python

random.choice (seq)

Return a random element from the non-empty sequence seq.

random.sample (совокупность, k)

Return a k length list of unique elements chosen from the population
sequence. Used for random sampling without replacement.

Использование:

>>> import random
>>> random.choice([1, 2, 3, 4, 5])  # Choose a random element
3
>>> random.sample([1, 2, 3, 4, 5],  3)  # Choose 3 elements
[4, 1, 5]

SQL

Предложение SQL WHERE

Предложение WHERE используется для извлечения только тех записей, которые соответствуют указанному критерию.

Использование:

SELECT * FROM Items
WHERE Type=1
person machine yearning    schedule 25.10.2011