【问题标题】:Python3 Uniquify list of tuples based on only one of the values of the indexPython3 仅基于索引值之一的唯一元组列表
【发布时间】:2014-11-04 03:50:55
【问题描述】:

我发誓我首先搜索了 SO,发现了很多“如果适应就可以工作”,但没有什么能真正帮助我。我所拥有的是以下形式的元组列表:

[('', 'noreply@bookfresh.com'), ('Andrea', 'andrea@aaa.com'), ('Your Book', 'noreply@bookfresh.com'), ..]

在这种情况下,它是一个元组列表,在所有索引中,第一个值是“Name”,第二个值是“Email”。并且列表没有以任何特定方式排序(还)。

我需要的是一种清晰且易于理解(我不一定要寻找我什至无法阅读的单行)的方式来生成“唯一”列表,但要遵循以下规则/注意事项:

  • 只有在发现元组的第二个值重复时才删除元组(在这种情况下,它恰好是一个电子邮件地址,它应该是“noreply@bookfresh.com”)
  • 不要消除所有重复元组的实例。我需要保留一个,而要保留的应该是第一个对象的 len() 最多的元组。 (在这种情况下,对于重复的元组,它将只保留元组('Your Book', 'noreply@bookfresh.com')。

这个最小化示例的最终输出是:

[('Andrea', 'andrea@aaa.com'), ('Your Book', 'noreply@bookfresh.com'), ..]

输出没有排序或排序无关紧要,因为我知道如何对未排序的元组列表进行排序。谢谢

【问题讨论】:

    标签: python list python-3.x tuples


    【解决方案1】:

    方法一:收集所有名字

    如果我们想要最容易理解的版本,而不是最流畅的版本,可能是这样的

    pairs = [('', 'noreply@bookfresh.com'), ('Andrea', 'andrea@aaa.com'), ('Your Book', 'noreply@bookfresh.com')]
    
    data = {}
    for name, email in pairs:
        if email not in data:
            data[email] = []
        data[email].append(name)
    
    output = [(email, max(data[email], key=len)) for email in data]
    

    会起作用的。这将问题分为两部分:构建一个以电子邮件地址为键和一个可能的名称列表作为值的字典;并遍历所有电子邮件地址并获取最长的名称。

    第一部分可以使用setdefault进行压缩,例如

    for name, email in pairs:
        data.setdefault(email, []).append(name)
    

    但并不是每个人都熟悉这一点。


    方法#2:排序并使其唯一

    或者,我们可以同时按电子邮件和姓名长度排序,然后从中构建一个字典,只保留最后看到的键/值对:

    >>> pairs.sort(key=lambda x: (x[1], len(x[0])))
    >>> data = {v: k for k,v in pairs}
    >>> [(v,k) for k,v in data.items()]
    [('Andrea', 'andrea@aaa.com'), ('Your Book', 'noreply@bookfresh.com')]
    

    【讨论】:

    • 感谢您解释这两种方法,它有助于想象试图抽象自己的问题。我正在实施#2,尽管它完成了工作,谢谢:)
    【解决方案2】:

    您可以使用第二个条目作为键来构建字典。字典具有在其键中不包含任何重复项的适当性。如果您在构建字典之前按第一个元素的长度排序,它将为您提供所需的内容:

    your_list_sorted = sorted(your_list, key=lambda x: len(x[0]))
    out = dict((v, k) for k, v in your_list_sorted)
    

    如果您需要列表形式的输出,可以通过out_list = list(out.items()) 获取。

    【讨论】:

    • 我最终使用了下面@DSM 提出的类似方法,它使用了字典。但是,在您的情况下,它反转了它,因此这是一个额外的步骤。但是您的答案显然也有效,所以+1。
    【解决方案3】:

    可能最简单的方法是使用这样的集合:

    L = [('', 'noreply@bookfresh.com'), ('Andrea', 'andrea@aaa.com'), ('Your Book', 'noreply@bookfresh.com'), ..]
    
    emails = set()
    
    result_L = []
    
    for item in L:
        if item[1] in emails:
            # this email address is already seen
            continue
    
        result_L += [item]
        emails.add(item[1])
    

    但是,如果你想保留最后一项,你可以使用这个(最后,你可能想反转result_L):

    for i in reversed(L):
        # ...
    

    还有很多其他方法可以做到这一点。例如,考虑使用dict

    result_dict = {}
    
    for item in L:
        result_dict[item[1]] = item[0]
    
    result_L = [(y, x) for (x, y) in result_dict.items()] 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-15
      • 2021-01-12
      • 2019-09-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多