8

So I have the following list:

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

Now I want to take the unique values from the list and print them on the screen. I've tried using the set function, but that doesn't work (Type error: unhasable type: 'list'), because of the [1,2] and [2,3] values in the list. I tried using the append and extend functions, but didn't come up with a solution yet.

expectation: ['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))   
Krofighter
  • 99
  • 1
  • 5
  • Can you elaborate on how your code "doesn't work"? What were you expecting, and what actually happened? If you got an exception/error, post the line it occurred on and the exception/error details. Please [edit] these details in or we may not be able to help. We won't know how to make the changes to your existing code base without seeing your original code. Please post a [mcve], and fully explain what needs to be modified. – Patrick Artner Mar 02 '19 at 23:54
  • Edited my post thank for notifying me. – Krofighter Mar 02 '19 at 23:58
  • Lists can't be an element of a set (or as a key to a dictionary as the duplicate notes). – Carcigenicate Mar 03 '19 at 00:45

5 Answers5

5

If the list contains unhashable elements, create a hashable key using repr that can be used with a set:

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)
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
4

You can use a simple for loop that appends only new elements:

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]]
iz_
  • 15,923
  • 3
  • 25
  • 40
0

You could do it in a regular for loop that runs in 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

There's also probably a way to finagle this into a list comprehension, which would be more elegant, but I can't figure it out at the moment. If every element was hashable you could use the set method and that would be easier.

Green Cloak Guy
  • 23,793
  • 4
  • 33
  • 53
0

One approach that solves this in linear time is to serialize items with serializers such as pickle so that unhashable objects such as lists can be added to a set for de-duplication, but since sets are unordered in Python and you apparently want the output to be in the original insertion order, you can use dict.fromkeys instead:

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

so that given your sample input, this returns:

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

Note that if you're using Python 3.6 or earlier versions where key orders of dicts are not guaranteed, you can use collections.OrderedDict in place of dict.

blhsing
  • 91,368
  • 6
  • 71
  • 106
  • 1
    Thank you for answering. I'm kind of limited to the basic functions of python: while, for, if, append, etc. So I didn't know that there was a function like this, but I'll take a look at it and debug it to understand it better. – Krofighter Mar 03 '19 at 00:28
0

To get the unique items from a list of non-hashables, one can do a partition by equivalence, which is a quadratic method as it compares each items to an item in each of the partitions and if it isn't equal to one of them it creates a new partition just for that item, and then take first item of each partition.

If some of the items are hashable, one can restrict the partition of equivalence to just the non-hashables. And feed the rest of the items through a set.

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)]

Untested.

Dan D.
  • 73,243
  • 15
  • 104
  • 123