Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Sort a list of objects based on the index of the object's property from another list

I have a tuple, RELAY_PINS that holds GPIO pin numbers in the order that the relays are installed. RELAY_PINS is immutable, and its ordering does not change, while the order that the devices are defined in changes frequently.

The MRE:

from random import shuffle, randint

class Device:
    def __init__(self, pin_number):
        self.pin_number = pin_number

    def __str__(self):
        return str(self.pin_number)

RELAY_PINS = ( 14, 15, 18, 23, 24, 25, 1, 12, 16, 20, 21, 26, 19, 13, 6, 5 )

def MRE():
    devices = [ Device(pin) for pin in RELAY_PINS ]

    # each GPIO pin might not have a device assigned, thus the MRE needs to emulate that
    devices.pop(randint(1, len(RELAY_PINS)))

    # the ordering for the list of devices should be considered random for the sake of this question
    shuffle(devices)
    return devices

My solution "works", but frankly, it’s embarrassing:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

def main():
    devices = MRE()
    pin_map = { pin_number : index for index, pin_number in enumerate(RELAY_PINS) }

    ordered_devices = [ None for _ in range(len(RELAY_PINS)) ]

    for device in devices:
        index = pin_map[device.pin_number]
        ordered_devices[index] = device

    return [ dev for dev in ordered_devices if dev is not None ]

I know there is a better solution, but I can’t quite wrap my head around it.

What is the pythonic solution to this problem?

>Solution :

You can use sorted with a key function:

from random import randint, shuffle


class Device:

  def __init__(self, pin_number: int):
    self.pin_number = pin_number

  def __str__(self) -> str:
    return str(self.pin_number)

  def __repr__(self) -> str:
    return f'Device(pin_number={self.pin_number})'


RELAY_PINS: tuple[int, ...] = (14, 15, 18, 23, 24, 25, 1, 12, 16, 20, 21, 26,
                               19, 13, 6, 5)


def MRE() -> None:
  devices = [Device(pin) for pin in RELAY_PINS]
  devices.pop(randint(0, len(RELAY_PINS) - 1))
  shuffle(devices)
  return devices


def main() -> None:
  devices = MRE()
  ordered_devices = sorted(devices, key=lambda d: RELAY_PINS.index(d.pin_number))
  print(ordered_devices)


if __name__ == '__main__':
  main()

Example Output (device with pin_number=12 randomly popped):

[Device(pin_number=14), Device(pin_number=15), Device(pin_number=18), Device(pin_number=23), Device(pin_number=24), Device(pin_number=25), Device(pin_number=1), Device(pin_number=16), Device(pin_number=20), Device(pin_number=21), Device(pin_number=26), Device(pin_number=19), Device(pin_number=13), Device(pin_number=6), Device(pin_number=5)]
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading