Sorting a linked list based on two values

I have a singly linked list, where the data is a custom object I've created, named 'Patient', and I sort the linked list based on the 'Patient.points'.

however, I want to also sort the list by 'Patient.bmi', as a secondary filter, if the two patients being compared have the same number of points.

the way I want to paitents to be sorted by the BMI filter is to have the patients with the worst bmi top, going in ascending order. I have four 'conditions', 'obese, overweight, underweight and normal'. I want obese, overweight and normal as descending order, and underweight in ascending order.

this is my linked list:

class Node:
    def __init__(self):
        self.data = None
        self.next = None

class LinkedList:
    def __init__(self):
        self.head = None

    def addNode(self, data):
        curr = self.head
        if curr is None:
            n = Node()
            n.data = data
            self.head = n
            return

        if curr.data.points == data.points and curr.data.condition == 'underweight':
            if curr.data.bmi > data.bmi:
                n = Node()
                n.data = data
                n.next = curr
                self.head = n
                return
        elif curr.data.points == data.points and curr.data.condition != 'underweight':
            if curr.data.bmi < data.bmi:
                n = Node()
                n.data = data
                n.next = curr
                self.head = n
                return

        if curr.data.points < data.points:
            n = Node()
            n.data = data
            n.next = curr
            self.head = n
            return

        while curr.next is not None:
            if curr.next.data.points < data.points:
                break
            curr = curr.next
        n = Node()
        n.data = data
        n.next = curr.next
        curr.next = n
        return

    def __str__(self):
        data = []
        curr = self.head
        while curr is not None:
            data.append(curr.data)
            curr = curr.next
        return "[%s]" %(', '.join(str(i) for i in data))

    def __repr__(self):
        return self.__str__()

and this is the data that gets returned:

Paitent name: BDF237    age: 79 Years 2 Months 14 Days      BMI: 37.960398071201396     weight classification: obese
Paitent name: ABE127    age: 20 Years 6 Months 20 Days      BMI: 34.54054238911118      weight classification: obese
Paitent name: ABD721    age: 73 Years 4 Months 25 Days      BMI: 31.217481789802285     weight classification: obese
Paitent name: DED567    age: 58 Years 5 Months 5 Days       BMI: 32.74416118146279      weight classification: obese
Paitent name: DEF444    age: 24 Years 11 Months 25 Days     BMI: 31.462672275229988     weight classification: obese
Paitent name: BDF777    age: 93 Years 10 Months 11 Days     BMI: 14.705367459122582     weight classification: underweight
Paitent name: BDF098    age: 86 Years 0 Months 13 Days      BMI: 13.863739248528747     weight classification: underweight
Paitent name: DDC345    age: 54 Years 3 Months 19 Days      BMI: 16.45600644235146      weight classification: underweight
Paitent name: DDD222    age: 73 Years 9 Months 0 Days       BMI: 18.166204254194742     weight classification: underweight
Paitent name: DDD555    age: 66 Years 10 Months 0 Days      BMI: 17.632653061224488     weight classification: underweight

Paitent name: DEF666    age: 65 Years 10 Months 22 Days     BMI: 17.68978885166924      weight classification: underweight
Paitent name: ABE123    age: 69 Years 6 Months 19 Days      BMI: 28.010411951109102     weight classification: overweight
Paitent name: ABD111    age: 72 Years 8 Months 0 Days       BMI: 26.122448979591837     weight classification: overweight
Paitent name: ABE165    age: 23 Years 3 Months 9 Days       BMI: 26.491508201480624     weight classification: overweight
Paitent name: ABE329    age: 82 Years 0 Months 7 Days       BMI: 25.46401086464464      weight classification: overweight
Paitent name: DDD124    age: 44 Years 6 Months 27 Days      BMI: 27.15271058955713      weight classification: overweight
Paitent name: DED675    age: 45 Years 6 Months 29 Days      BMI: 28.735632183908045     weight classification: overweight
Paitent name: DED879    age: 22 Years 9 Months 1 Days       BMI: 28.73469387755102      weight classification: overweight
Paitent name: DEF555    age: 27 Years 1 Months 24 Days      BMI: 25.847768218818715     weight classification: overweight
Paitent name: ABC234    age: 19 Years 7 Months 19 Days      BMI: 23.057725694444446     weight classification: normal

Paitent name: ABD221    age: 50 Years 11 Months 0 Days      BMI: 21.872422819032593     weight classification: normal
Paitent name: ABD176    age: 55 Years 11 Months 3 Days      BMI: 21.132713440405748     weight classification: normal
Paitent name: ABD231    age: 55 Years 11 Months 29 Days     BMI: 20.9572742022715       weight classification: normal
Paitent name: ABD321    age: 59 Years 11 Months 9 Days      BMI: 20.429418362441915     weight classification: normal
Paitent name: ABD444    age: 57 Years 5 Months 6 Days       BMI: 20.820939916716245     weight classification: normal
Paitent name: ABD401    age: 63 Years 9 Months 22 Days      BMI: 21.513858510523864     weight classification: normal
Paitent name: ABD007    age: 22 Years 2 Months 17 Days      BMI: 21.62964876033058      weight classification: normal
Paitent name: ABC008    age: 83 Years 1 Months 19 Days      BMI: 19.77769866698311      weight classification: normal
Paitent name: ABC101    age: 86 Years 0 Months 13 Days      BMI: 18.556773222226116     weight classification: normal
Paitent name: ABC201    age: 26 Years 10 Months 7 Days      BMI: 20.303697560696612     weight classification: normal

I believe the issue is in my linked list class in the while class:

while curr.next is not None:
            if curr.next.data.points < data.points:
                break

However, I'm not sure what I would need to adjust it to, although I do know it needs adjusting

Many thanks in advance!

Upvotes: 0

Views: 62

Answers (2)

Oliver
Oliver

Reputation: 94

Define __lt__ to compare the conditions in order:

def __lt__(self, other):
    if self.Points < other.Points:
        return True
    elif self.Points == other.Points:
        if self.bmi < other.bmi:
            return True
        else:
            return False
    else: # self.Points > other.Points
        return False

Upvotes: 0

Kenny Ostrom
Kenny Ostrom

Reputation: 5871

You don't want your linked list to worry about how to compare the patients. Simply override the < operator for the patient class, so that comparing two patients will automatically give the order you want.

Now your linked list class doesn't care about all those fancy rules, because they are handled by the Patient class, as they should be. The linked list just checks

while curr.next is not None:
    if curr.next.data < data:
        break

The way you do this is you define a function named __lt__ on the Patient class. The letters "lt" are short for "less than" and will be used when you use "<" in your code. Similarly, it will automatically be referenced in a sort.

see also Is it possible to overload the multiple comparison syntax in python?

Here's a quick demo:

import random

class Patient:

    def __init__(self, points, bmi):
        self.points = points
        self.bmi = bmi
        
    def __str__(self):
        return '{}, {}'.format(self.points, self.bmi)

    def __lt__(self, other):
        if self.points < other.points:
            return True
        if self.bmi < 18.5:
            if self.bmi > other.bmi:
                return True
        else:
            if self.bmi < other.bmi:
                return True
        return False

patients = [
    Patient(32, 25),
    Patient(32, 24),
    Patient(32, 18),
    Patient(32, 15),
    Patient(20, 25),
    Patient(20, 24),
    Patient(20, 18),
    Patient(20, 15),
]

random.shuffle(patients)
patients.sort()
for patient in patients:
    print(patient)

20, 18
20, 15
20, 24
20, 25
32, 18
32, 24
32, 15
32, 25

Upvotes: 1

Related Questions