Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a list in Python distinct based on a property of the class in the list?

I have a list of instances from the same class, and I want to make my list distinct based on a property in the class. What is the most pythonic way to achieve this?

Here is some sample code:

#!/usr/bin/python
#-*- coding:utf-8 -*-

class MyClass(object):
    def __init__(self, classId, tag):
        self.classId = classId
        self.tag = tag

myList = []

myInstance1 = MyClass(1, "ABC")
myInstance2 = MyClass(2, "DEF")
myInstance3 = MyClass(3, "DEF")

myList.append(myInstance1)
myList.append(myInstance3) # note that the order is changed deliberately
myList.append(myInstance2)

If I want to sort my list now based on one of the properties in MyClass, I usually just sort it by key, and set the key using a lambda expression - like this:

myList.sort(key=lambda x: x.classId)
for x in myList:
    print x.classId

$ python ./test.py
1
2
3

Is it possible to use a similar method (lambda, map or similar) to make the list distinct based on the "tag" property? Also, if this is possible, is it the most "pythonic" way to make a list distinct based on a property of a class in that list?

I have already tried searching both SO and Google for topics on this matter, but all the results I found dealt with simple lists that only contained a numeric value and not a custom object..

like image 743
v3gard Avatar asked Jun 03 '13 14:06

v3gard


People also ask

How do you distinct a list in Python?

Using Python's import numpy, the unique elements in the array are also obtained. In the first step convert the list to x=numpy. array(list) and then use numpy. unique(x) function to get the unique values from the list.

How do you count unique values in a list?

You can use the combination of the SUM and COUNTIF functions to count unique values in Excel. The syntax for this combined formula is = SUM(IF(1/COUNTIF(data, data)=1,1,0)). Here the COUNTIF formula counts the number of times each value in the range appears.


2 Answers

You can use python dict comprehension

{x.tag: x for x in myList}.values()

For your example:

>>> class MyClass(object):
...     def __init__(self, classId, tag):
...         self.classId = classId
...         self.tag = tag
...
>>> myList = [MyClass(1, "ABC"), MyClass(2, "DEF"), MyClass(3, "DEF")]
>>> uniqList = {x.tag: x for x in myList}.values()
>>> print [x.classId for x in uniqList]
[1, 3]
like image 50
Max Kamenkov Avatar answered Oct 23 '22 04:10

Max Kamenkov


Assuming the property you wish to key on is immutable, you can use a dict:

d = {}
for x in xs:
    d[x.tag] = x

Now d will contain a single x per tag value; you can use d.values() or d.itervalues() to get at the xs.

NB. here last matching item wins; to have the first one win, iterate in reverse.

like image 42
Michał Marczyk Avatar answered Oct 23 '22 03:10

Michał Marczyk