1

我想生成具有以下条件的大小为 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], ...]
4

2 回答 2

3

我认为以下策略可以满足您的要求:

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

这里的想法是我们生成一些提供正确元素的东西,然后我们将它转​​换成正确形状的东西。我们不是尝试生成整数列表对,而是生成一个唯一整数列表,然后将它们分组为对(如果有奇数个整数,我们删除最后一个元素)。然后我们对每一对进行排序以确保其顺序正确。

于 2018-04-11T08:21:52.967 回答
2

David 的解决方案允许一个整数出现在两个子列表中 - 对于完全唯一的整数,我将使用以下内容:

@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 个可能的唯一元素),您可能会通过创建可能元素列表并从中弹出而不是拒绝来获得更好的性能看到的元素。
于 2018-04-12T07:18:11.470 回答