【问题标题】:Combining two sets and splitting them in pairs组合两组并成对拆分
【发布时间】:2012-01-07 03:04:14
【问题描述】:

我需要获取两组数据并从两组中生成一组对(元组)。这个结果集只有一个可能的对,即对于两个集合:1,2 和 3, 4,结果应该是:((1, 3), (2, 4))。完整的练习文本可以在这里找到:http://pastebin.com/mUaKV4G7

我需要使用 pop 来执行此操作。这是我目前所拥有的:

def mating_pairs(males, females):
    pairs = set()
    tmp_males, tmp_females = males.copy(), females.copy()
    for male in tmp_males:
        for female in tmp_females:
            pairs.add(males.pop())
            pairs.add(females.pop())
        zip(pairs[::2], pairs[1::2])
        return pairs

这个函数可以正常工作,直到它到达:

        zip(pairs[::2], pairs[1::2])

如果没有它,它会将它们组合在一起,但是当我尝试使用 zip 将它们成对拆分时,我得到了这个错误:

'set' object is not subscriptable

这让我相信它在某处返回 None 而不是正确的结果。

此函数需要同时处理整数和字符串(我认为它不需要按特定顺序配对值),而且两个集合的值数量相同。

有人可以告诉我我做错了什么吗?

【问题讨论】:

  • 您是否需要生成所有可能的对,将第一个集合中的每个元素与第二个集合中的每个元素组合在一起?
  • @KL-7 不,只需使用 pop 将第一个值与第二个值配对
  • @Andrew Marsh,这不是家庭作业,而是我正在学习的书中的练习。
  • 能否请您修复您发布的代码中的标识?最后两行应该在什么标识级别上并不明显。
  • 我假设您使用的是pop,因为问题告诉您这样做?如果是这样,请记住,这只是一个帮助您思考数据结构操作的练习 - 您永远不会实际上在实际代码中使用 pop 来执行此操作。

标签: python tuples set


【解决方案1】:

我有点不确定你想做什么。但是分析您发布的代码,我猜您想将每个男性与每个女性组合一次,并将每个组合的元组放入最终列表中。

如果是这种情况,那么您要做的就是创建一个Cartesian product。 Python 库为此提供了一个很好的函数:itertools.product。你可以这样使用它:

def mating_pairs(males, females):
    return set(itertools.product(males, females))

如果您想以手动方式执行此操作,则可以使用两个嵌套的 for 循环来获取所有组合。但是,您使用pop 的方式是行不通的。您在代码中所做的是迭代所有男性和女性(在复制参数之后),然后从原始集合中弹出项目。这样一来,malesfemales 的两个集合很快就会为空,因为您会不断从它们中弹出每个可能的组合,而不考虑如果您继续重复使用单个项目,您只会获得所有组合。

你可以像这样修复你的代码,而不使用 pop:

def mating_pairs(males, females):
    pairs = set()

    # We only iterate over the items, so we don’t modify the original sets.
    for male in males:
        for female in females:
            # And instead of adding individual items by once, and zipping them
            # later, we just directly add tuples to the set.
            pairs.add((male, female))

    return pairs

【讨论】:

  • 我只需要将一名女性与一名男性结合起来,因此对于 2 组:1,2 和 3,4,结果将是 ((1, 3), (2, 4))跨度>
【解决方案2】:

如果使用 pop 是强制限制,我会采用类似的方式:

def mating_pairs(males, females):
    res = set()
    males_copy, females_copy = males.copy(), females.copy()

    while males_copy and females_copy:
        res.add((males_copy.pop(), females_copy.pop()))

    return res

print mating_pairs(set([1, 2, 3]), set(['a', 'b', 'c', 'd']))
# => set([(1, 'a'), (2, 'b'), (3, 'c')])

set(zip(males, females)) 无论如何要容易得多。

【讨论】:

    【解决方案3】:

    如果您必须使用 pop,请尝试同时将 malesfemales 弹出到您添加到 pairs 的元组中(顺便说一下,我不确定您为什么要复制您的设置并销毁原件,但我想你有你的理由)。此外,同时迭代 malesfemales 将无法为您提供您正在寻找的答案 - 相反,当您从中弹出时检查每个集合的空虚。您正在寻找的更像是这样的:

    def mating_pairs(males, females):
        pairs = set()
        tmp_males, tmp_females = males.copy(), females.copy()
        while tmp_males and tmp_females:
            pairs.add((tmp_males.pop(),tmp_females.pop()))
        return pairs
    

    如果您可以避免使用set.pop,这会更简单:

    def mating_pairs(males, females):
        return set(zip(males,females))
    

    另外,请注意,除非您使用某种有序集数据类型,否则这不是一个完整的答案。由于它使用的是set,因此您不能保证保留传入的malesfemales 的任何顺序

    【讨论】:

    • 我复制了这些集合,以便能够迭代它们并同时更改原件。你的回答非常优雅,我会选择它,但之前的海报回答了我关于 zip 的问题。
    【解决方案4】:

    错误告诉您发生了什么:pairsset,而表达式 pairs[::2] 表示“集合的每个第二个元素”。问题是sets 没有定义的顺序,所以“集合的每个第二个元素”没有意义。由于元素的顺序未定义,Python 会引发异常而不是随机排列。

    您可能想要做的是将男性和女性按出现的顺序配对:

    def mating_pairs(males, females):
        return zip(males, females)
    

    或所有可能的男性和女性对(两个列表的乘积):

    from itertools import product
    def mating_pairs(males, females):
        return product(males, females)
    

    您的作业似乎是实现zipproduct :-)

    【讨论】:

    • 练习我没有提到这两个,你的回复回答了我的问题,谢谢。完整的练习文本可以在这里找到:pastebin.com/mUaKV4G7
    • @gameFace:这个练习实际上毫无意义。为什么要在生成输出集的同时清空输入集?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 2013-02-19
    • 2018-04-09
    • 2019-05-05
    • 1970-01-01
    相关资源
    最近更新 更多