Генерация условных данных с помощью гипотезы Python

Я хочу создать список списков целых чисел размера 2 со следующими условиями.

  • первый элемент должен быть меньше второго и
  • Все данные должны быть уникальными.

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

from hypothesis import strategies as st

@st.composite
def generate_data(draw):
    min_val, max_val = draw(st.lists(st.integers(1, 1e2), min_size=2, max_size=2))
    st.assume(min_val < max_val)
    return [min_val, max_val]

Я мог бы генерировать данные, перебирая generate_date несколько раз таким (неэффективным?) образом:

>>> [generate_data().example() for _ in range(3)]
    [[5, 31], [1, 12], [33, 87]]

Но как я могу проверить, что данные уникальны?

Например, следующие значения недопустимы:

[[1, 2], [1, 5], ...]  # (1 is repeated)
[[1, 2], [1, 2], ...]  # (repeated data)

но действует следующее:

[[1, 2], [3, 4], ...]

2 ответа

Решение

Я думаю, что следующая стратегия удовлетворяет вашим требованиям:

import hypothesis.strategies as st

@st.composite
def unique_pair_lists(draw):
    data = draw(st.lists(st.integers(), unique=True)
    if len(data) % 2 != 0:
        data.pop()
    result = [data[i:i+2] for i in range(0, len(data), 2)]
    for pair in result:
        pair.sort()
    return result

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

Решение Дэвида позволяет целому числу появляться в двух подсписках - для полностью уникальных целых я бы использовал следующее:

@st.composite
def list_of_pairs_of_unique_elements(draw):
    seen = set()
    new_int = st.integers(1, 1e2)\
        .filter(lambda n: n not in seen)\  # Check that it's unique
        .map(lambda n: seen.add(n) or n)   # Add to filter before next draw
    return draw(st.lists(st.tuples(new_int, new_int).map(sorted))
  • .filter(...) Метод, вероятно, то, что вы ищете.
  • .example() только для интерактивного использования - вы получите предупреждение (или ошибку), если вы используете его в @given(),
  • Если бы вы могли отфильтровать большинство элементов в диапазоне (например, внешний список длиной> 30, что означает 60/100 возможных уникальных элементов), вы могли бы получить более высокую производительность, создав список возможных элементов и выбрав его, а не отклоняя видимые элементы.
Другие вопросы по тегам