1

I'm attempting to create functions that'll allow me to get a list of the unique sublists of a list. The functions are working for some lists of lists and not for others and I'm not sure why.

What would be a working, robust way to get the indices of the duplicate sublists and then to build a list of them?

The following minimal working example illustrates the functionality. The duplicates are found for list a but found incorrectly for list b.

def indices_of_list_element_duplicates(x):
    seen = set()
    for index, element in enumerate(x):
        if isinstance(element, list):
            element = tuple(element)
        if element not in seen:
            seen.add(element)
        else:
            yield index

def list_element_duplicates(x):
    indices = list(indices_of_list_element_duplicates(x))
    return [x[index] for index in indices]

a = [[1, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [5, 2]]

print(list_element_duplicates(a))

print("--------------------------------------------------------------------------------")

b = [[10], [15], [20], [10, 10], [10, 15], [10, 20], [15, 10], [15, 15], [15, 20], [20, 10], [20, 15], [20, 20], [10, 10, 10], [10, 10, 15], [10, 10, 20], [10, 15, 10], [10, 15, 15], [10, 15, 20], [10, 20, 10], [10, 20, 15], [10, 20, 20], [15, 10, 10], [15, 10, 15], [15, 10, 20], [15, 15, 10], [15, 15, 15], [15, 15, 20], [15, 20, 10], [15, 20, 15], [15, 20, 20], [20, 10, 10], [20, 10, 15], [20, 10, 20], [20, 15, 10], [20, 15, 15], [20, 15, 20], [20, 20, 10], [20, 20, 15], [20, 20, 20], [10], [15], [20], [10, 10], [10, 15], [10, 20], [15, 10], [15, 15], [15, 20], [20, 10], [20, 15], [20, 20], [10, 10, 10], [10, 10, 15], [10, 10, 20], [10, 15, 10], [10, 15, 15], [10, 15, 20], [10, 20, 10], [10, 20, 15], [10, 20, 20], [15, 10, 10], [15, 10, 15], [15, 10, 20], [15, 15, 10], [15, 15, 15], [15, 15, 20], [15, 20, 10], [15, 20, 15], [15, 20, 20], [20, 10, 10], [20, 10, 15], [20, 10, 20], [20, 15, 10], [20, 15, 15], [20, 15, 20], [20, 20, 10], [20, 20, 15], [20, 20, 20], [10], [15], [20], [10, 10], [10, 15], [10, 20], [15, 10], [15, 15], [15, 20], [20, 10], [20, 15], [20, 20], [10, 10, 10], [10, 10, 15], [10, 10, 20], [10, 15, 10], [10, 15, 15], [10, 15, 20], [10, 20, 10], [10, 20, 15], [10, 20, 20], [15, 10, 10], [15, 10, 15], [15, 10, 20], [15, 15, 10], [15, 15, 15], [15, 15, 20], [15, 20, 10], [15, 20, 15], [15, 20, 20], [20, 10, 10], [20, 10, 15], [20, 10, 20], [20, 15, 10], [20, 15, 15], [20, 15, 20], [20, 20, 10], [20, 20, 15], [20, 20, 20], [10], [15], [20], [10, 10], [10, 15], [10, 20], [15, 10], [15, 15], [15, 20], [20, 10], [20, 15], [20, 20], [10, 10, 10], [10, 10, 15], [10, 10, 20], [10, 15, 10], [10, 15, 15], [10, 15, 20], [10, 20, 10], [10, 20, 15], [10, 20, 20], [15, 10, 10], [15, 10, 15], [15, 10, 20], [15, 15, 10], [15, 15, 15], [15, 15, 20], [15, 20, 10], [15, 20, 15], [15, 20, 20], [20, 10, 10], [20, 10, 15], [20, 10, 20], [20, 15, 10], [20, 15, 15], [20, 15, 20], [20, 20, 10], [20, 20, 15], [20, 20, 20]]

print(list_element_duplicates(b))
d3pd
  • 7,935
  • 24
  • 76
  • 127

4 Answers4

1

You could use a Counter dict mapping the sublists to tuple and get the counts only keeping the sublists whose count is > 1:

from collections import Counter
a = [[1, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [5, 2]]


cn = Counter(map(tuple,a))

print([sub for sub in a if cn[tuple(sub)] > 1])

to work for mixed types and get unique returns:

from collections import Counter    

a = [[1, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [5, 2], "foo", 123, 123]

def counts(x):
    for ele in x:
        if isinstance(ele, Hashable):
            yield ele
        else:
            yield tuple(ele)


def unique_dupes(x):
    cnts = Counter(counts(x))
    for ele in x:
        t = ele
        if not isinstance(ele, Hashable):
            t = tuple(ele)
        if cnts[t] > 1:
            yield ele
            del cnts[t]

print(list(unique_dupes(a)))

Output:

 [[1, 2], [5, 2], 123]
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
0

The issue must come from these lines:

if isinstance(element, list):
    element = tuple(element)
if element not in seen:
    seen.add(element)

So what happens is if you had already in seen say for example [10,15] and then you want to check [15,10] in seen, it will return FALSE.

A fix for that and while you consider [x,y] to be the same as [y,x], is to sort each element you check, this way:

if isinstance(element, list):
    element = tuple(sorted(element))
if element not in seen:
    seen.add(element)
Iron Fist
  • 10,739
  • 2
  • 18
  • 34
0

Its easy with list comprehension

list_a = [[1, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [5, 2]]

    unique_list=[]
    duplicate_list=[]
    sorted_list=[sorted(item) for item in list_a]

    final_list=[unique_list.append(item) if item not in unique_list else duplicate_list.append(item) for item in sorted_list]
    print(unique_list)
    print(duplicate_list)
Aaditya Ura
  • 12,007
  • 7
  • 50
  • 88
-1

Python lists have a beautiful built in function for this called count. Using this you can do:

a = [[1, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [5, 2]]
dups = list()

for e in a:
    if a.count(e) > 1:
        dups.append(e)

This will give you a list called dups containing [[1,2],[1,2],[5,2],[5,2]]

m_callens
  • 6,100
  • 8
  • 32
  • 54