Συζήτηση
Γεια χαρά, Επισκέπτης
Όνομα χρήστη: Κωδικός: Να με θυμάσαι

ΘΕΜΑ: Custom_sort

Custom_sort 6 Χρόνια 9 Μήνες πριν #5037

  • Theo
  • Το Άβαταρ του/της Theo
  • Αποσυνδεμένος
  • pytho_
  • Δημοσιεύσεις: 249
  • Ληφθείσες Ευχαριστίες 70
Παιδειά βάζω εδώ ένα παράδειγμα custom_sort μια που έχουμε καινούργιο κόσμο
Το ανέβασα και στο insomnia.gr
Κατ' αρχήν η δουλειά γίνεται με την sorted https://docs.python.org/3/library/functions.html#sorted
 
sorted(iterable, *, key=None, reverse=False) και όλη η ουσία είναι η key function.
Έστω ότι έχω την παρακάτω λίστα και θέλω να την ταξινομήσω 1α μηχανικοί 
μετά προγραμματιστές μετά γραφίστες μηχανικός < προγραμματιστής > γραφίστας 
οπότε πρέπει να κάνω κάτι custom
 
my_list = [	(1, 'Γιάννης', 35, 'Μηχανικός'),
			(2, 'Γιώργος', 38, 'Προγραμματιστής'),
			(3, 'Κώστας', 48, 'Γραφίστας'),
			(4, 'Αλέκος', 24, 'Μηχανικός'),
			(5, 'Παναγιώτης', 32, 'Γραφίστας'),
			(6, 'Κυριάκος', 27, 'Γραφίστας'),
			(7, 'Μιχάλης', 23, 'Μηχανικός'),
			(8, 'Παναγιώτης', 55, 'Προγραμματιστής'),
			(9, 'Γιάννης', 31, 'Μηχανικός')]
 
Κάνω λοιπόν μια συνάρτηση που πρέπει να πέρνει ένα μόνο όρισμα. 
Το όρισμα αυτό πρέπει να είναι της μορφής που είναι τα στοιχεία της λίστας
 
def custom_sort(object):
	if object[3]=='Μηχανικός':
		return 1
	elif object[3]=='Προγραμματιστής':
		return 2
	elif object[3]=='Γραφίστας':
		return 3
	else:
		return 4
 
και αυτό είναι όλο
 
sorted (my_list, key = custom_sort)
[(1, 'Γιάννης', 35, 'Μηχανικός'), (4, 'Αλέκος', 24, 'Μηχανικός'), (7, 'Μιχάλης', 23, 'Μηχανικός'), (9, 'Γιάννης', 31, 'Μηχανικός'), (2, 'Γιώργος', 38, 'Προγραμματιστής'), (8, 'Παναγιώτης', 55, 'Προγραμματιστής'), (3, 'Κώστας', 48, 'Γραφίστας'), (5, 'Παναγιώτης', 32, 'Γραφίστας'), (6, 'Κυριάκος', 27, 'Γραφίστας')]
>>> 
 
Υπάρχει και πιο απλός τρόπος να κάνεις το συγκεκριμένο χωρίς να γράψεις συνάρτηση. 
Ο παραπάνω όμως τρόπος σε καλύπτει για όλες τις περιπτώσεις 
Τελευταία διόρθωση: 6 Χρόνια 9 Μήνες πριν από Theo.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Custom_sort 6 Χρόνια 8 Μήνες πριν #5058

  • n_karag
  • Το Άβαταρ του/της n_karag
  • Αποσυνδεμένος
  • py____
  • Software Developer at BMLL Technologies, London,UK
  • Δημοσιεύσεις: 9
  • Ληφθείσες Ευχαριστίες 2
Υπάρχει και πιο απλός τρόπος να κάνεις το συγκεκριμένο χωρίς να γράψεις συνάρτηση.
Ο παραπάνω όμως τρόπος σε καλύπτει για όλες τις περιπτώσεις

Υπάρχει ένα μικρό θέμα με τον παραπάνω τρόπο: κάθε φορά που θέλεις να προσθέσεις μία κατηγορία, θα πρέπει να τροποποιείς τη συνάρτηση custom_sort. Επίσης, η λογική if-elif-else δεν είναι πρακτική σε αυτή την περίπτωση, γιατί αν έχεις 50 κατηγορίες, θα πρέπει να βάλεις αντίστοιχο αριθμό κλάδων elif.

Αντί για συνάρτηση, μπορούμε να χρησιμοποιήσουμε ένα λεξικό:
job_order = {'Μηχανικός': 1, 'Προγραμματιστής': 2, 'Γραφίστας': 3}
 
sorted(my_list, key = lambda x: job_order.get(x[3], len(sd)+1))

όπου:
  • lambda <x>: <f(x)>
    δημιουργεί μία ανώνυμη συνάρτηση f(x) για μία παράμετρο x
  • <λεξικό>.get(<κλειδί>, <προεπιλεγμένη τιμή>)
    επιλέγει ένα κλειδί από ένα λεξικό και αν αυτό δεν υπάρχει, επιστρέφει την προεπιλεγμένη τιμή.

Η προεπιλεγμένη τιμή σε αυτή την περίπτωση είναι το μήκος του λεξικού συν 1 (ακολουθώντας τη λογική του else τμήματος στην εκδοχή του Theo)


Αυτή η τελευταία λεπτομέρεια μπορεί να ενσωματωθεί σε μία δική μας επέκταση του βασικού λεξικού, όπου μπορούμε να τροποποιήσουμε τη βασική μέθοδο __getitem__:
class MyDict(dict):
    def __getitem__(self, key):
        if key in self:
            return super().get(key)
        else:
            return len(self) + 1

Αν το κλειδί key υπάρχει στο MyDict, τότε το επιστρέφει από τις τιμές της βασικής κλάσης, που είναι το dict. Αν πάλι δεν υπάρχει το κλειδί, τότε επιστρέφει το νούμερο <πλήθος κλειδιών> + 1.

Οπότε τώρα μπορούμε να απλοποιήσουμε τη βασική υλοποίηση
job_order = MyDict({'Μηχανικός': 1, 'Προγραμματιστής': 2, 'Γραφίστας': 3})
 
sorted(my_list, key = lambda x: job_order[x[3]])


Τι κερδίσαμε με το παραπάνω;
Αν θέλουμε προσθαφαιρέσουμε επαγγέλματα, απλά αλλάζουμε το λεξικό, αντί να τροποποιούμε μία συνάρτηση. Επίσης, για μεγάλο αριθμό επαγγελμάτων, απλά έχουμε περισσότερα ζεύγη κλειδή-τιμή στο λεξικό, αντί για ένα τεράστιο μπλοκ εντολών if-elif-else.


Υ.Γ.

Αν κάποιος τώρα θέλει να χρησιμοποίσει συνάρτηση στην sorted, γιατί ίσως είναι φαίνεται πιο απλή η σύνταξη, τότε μπορεί να συνδυάσει τα παραπάνω:
def custom_sort(obj):
    return job_order[obj[3]]

Εδώ το λεξικό job_order θα πρέπει να χρησιμοποιηθεί σαν global μεταβλητή, που δεν είναι και η καλύτερη πρακτική.

Καλύτερα, θα μπορούσαμε να κάνουμε χρήση της partial από τη βασική βιβλιοθήκη functools
from functools import partial
 
def custom_sort(obj, d):
    return d[obj[3]]
 
sorted(my_list, key=partial(custom_sort, d=job_order)

όπου η συνάρτηση
partial(<συνάρτηση>, <παράμετρος της συνάρτησης>=<τιμή>, <παράμετρος της συνάρτησης>=<τιμή>, ...)

επιστρέφει μία συνάρτηση η οποία στην υπογραφή της έχει μόνο τις παραμέτρους που περισσέψανε, αν από όλες αφαιρέσουμε αυτές που καθορίσαμε. Πχ. το
partial(custom_sort, d=job_order)

επιστρέφει μια συνάρτηση ίδια με την custom_sort, αλλά υπογραφή custom_sort(obj) μόνο, καθώς έχουμε ήδη περάσει τιμή για την παράμετρο d.

Ένα τελευταίο σχόλιο: καλό είναι να μην χρησιμοποιούμε δεσμευμένες από την Python λέξεις, όπως το object.

Ελπίζω να βοήθησα.
Τελευταία διόρθωση: 6 Χρόνια 8 Μήνες πριν από n_karag.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Custom_sort 6 Χρόνια 8 Μήνες πριν #5084

  • Theo
  • Το Άβαταρ του/της Theo
  • Αποσυνδεμένος
  • pytho_
  • Δημοσιεύσεις: 249
  • Ληφθείσες Ευχαριστίες 70
Ωραία και μεγάλη ανάλυση :) με την partial λίγο το χάνω γιατί δεν την έχω χρησιμοποιήσει ποτέ

Ο σκοπός που έδειξα τον "χαζό" τρόπο είναι για να γίνει κατανοητή η λειτουργία του key=function. Εάν δει κάποιος απευθείας μια λύση με lambda είναι λίγο δύσκολο στην κατανόηση.

Εγώ το πρώτο πράγμα που σκέφτηκα είναι να βάλω τα στοιχεία σε ένα list με τη σειρά που θέλω και να πάρω το index τους
seira=['Μηχανικός','Προγραμματιστής','Γραφίστας']
sorted(my_list, key=lambda obj: seira.index(obj[3]))

Υποθέτω θα είναι πιο αργό απο το dictionary.
Τελευταία διόρθωση: 6 Χρόνια 8 Μήνες πριν από Theo.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Custom_sort 6 Χρόνια 8 Μήνες πριν #5085

  • n_karag
  • Το Άβαταρ του/της n_karag
  • Αποσυνδεμένος
  • py____
  • Software Developer at BMLL Technologies, London,UK
  • Δημοσιεύσεις: 9
  • Ληφθείσες Ευχαριστίες 2
Υποθέτω θα είναι πιο αργό απο το dictionary.

Είναι όπως ακριβώς το είπες, γιατί το <list>.index(<value>) είναι O(n), ενώ το <dict>[<key>] είναι O(1).

Αν πειραματιστείς λίγο σε idle/ipython/jupyter με την %timeit, θα δεις και τις διαφορές στους χρονους (δοκίμασε με 3, 300 και 30000 στοιχεία).
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.
Συντονιστές: pmav99
Χρόνος δημιουργίας σελίδας: 0.320 δευτερόλεπτα

Μοιράσου το!

Powered by CoalaWeb

Λίστα Ταχυδρομείου