使用不可哈希元素的列表,去除其中的唯一值

8

我有以下列表:

test_list = ['Hallo', 42, [1, 2], 42, 3 + 2j, 'Hallo', 'Hello', [1, 2], [2, 3], 3 + 2j, 42] 

现在我想从列表中获取唯一的值,并将它们打印在屏幕上。我尝试使用set函数,但是由于列表中具有[1,2]和[2,3]这样的值,所以出现了(TypeError:不可散列类型:'list')错误。我尝试使用append和extend函数,但还没有找到解决方案。

期望输出: ['Hallo', 42, [1,2], (3+2j), 'Hello', [2,3]]

def unique_list(a_list): 
    a = set(a_list)
    print(a)
a_list = ['Hallo', 42, [1, 2], 42, 3 + 2j, 'Hallo', 'Hello', [1, 2], [2, 3], 3 + 2j, 42]
print(unique_list(a_list))   

你能详细说明一下你的代码“为什么不工作”吗?你期望发生什么,实际上又发生了什么?如果你遇到了异常/错误,请发布它发生的行和异常/错误的详细信息。请编辑这些细节,否则我们可能无法提供帮助。我们不知道如何在看不到原始代码的情况下对现有代码库进行更改。请发布一个最小可复现示例,并完全解释需要修改的内容。 - Patrick Artner
我编辑了我的帖子,感谢您的提醒。 - Krofighter
列表不能作为集合的元素(或作为字典的键,因为会出现重复的注释)。 - Carcigenicate
所引用的“重复”问题并未说明如何在列表包含不可哈希元素时实际删除重复项 - undefined
那个问题似乎更适合作为重复问题的候选。 - undefined
5个回答

5

如果列表中包含不可哈希的元素,则可以使用 repr 创建一个可哈希的键,以便与集合一起使用:

def unique_list(a_list):
    seen = set()
    for x in a_list:
        key = repr(x)
        if key not in seen:
            seen.add(key)
            print(x)

4
您可以使用简单的for循环仅附加新元素:
test_list = ['Hallo', 42, [1, 2], 42, 3 + 2j, 'Hallo', 'Hello', [1, 2], [2, 3], 3 + 2j, 42]
new_list = []

for item in test_list:
    if item not in new_list:
        new_list.append(item)

print(new_list)
# ['Hallo', 42, [1, 2], (3+2j), 'Hello', [2, 3]]

0

你可以使用普通的 for 循环来完成,其时间复杂度为 O(n^2)。

def unique_list(a_list):
    orig = a_list[:]               # shallow-copy original list to avoid modifying it
    uniq = []                      # start with an empty list as our result
    while(len(orig) > 0):          # iterate through the original list
        uniq.append(orig[0])       # for each element, append it to the unique elements list
        while(uniq[-1] in orig):   # then, remove all occurrences of that element in the original list
            orig.remove(uniq[-1])
    return uniq                    # finally, return the list of unique elements in order of first occurrence in the original list

也许还有一种方法可以将其变成列表推导式,这样会更加优雅,但我目前想不出来。如果每个元素都是可哈希的,你可以使用set方法,那会更容易。


2
这绝对是二次而不是线性的时间复杂度。 - blhsing
谢谢您的评论。在更多的练习之后,这似乎是我可以想出的一个解决方案。 - Krofighter

0

解决这个问题的一种线性时间方法是使用序列化程序(如pickle)对项目进行序列化,以便将诸如列表之类的不可哈希对象添加到集合中进行去重。但由于在Python中集合是无序的,而您显然希望输出按照原始插入顺序排列,因此可以改用dict.fromkeys

import pickle
list(map(pickle.loads, dict.fromkeys(map(pickle.dumps, test_list))))

因此,根据您的示例输入,这将返回:

['Hallo', 42, [1, 2], (3+2j), 'Hello', [2, 3]]

请注意,如果您使用的是Python 3.6或更早版本,其中字典键的顺序不被保证,您可以使用collections.OrderedDict代替dict

1
谢谢您的回答。我在Python的基本函数方面有些受限,例如while、for、if、append等。因此,我不知道还有这样的一个函数,但我会查看并调试它以更好地理解它。 - Krofighter

0

要从一个非哈希列表中获取唯一的项,可以通过等价划分来实现,这是一种二次方法,因为它会将每个项与每个分区中的一项进行比较,如果它与其中任何一项不相等,则为该项创建一个新的分区,然后取每个分区的第一项。

如果其中一些项是可哈希的,则可以将等价划分限制为只针对非哈希项。并通过集合处理其余的项。

import itertools

def partition(L):
    parts = []
    for item in L:
        for part in parts:
            if item == part[0]:
               part.append(item)
               break
        else:
            parts.append([item])
    return parts

def unique(L):
    return [p[0] for p in partition(L)]

未测试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接