4 Stimmen

Positionale Rankings und Umgang mit Gleichständen in Python

(Es tut mir leid, dass in früheren Versionen dieser Frage die falsche Funktion angezeigt wurde, die ich korrigieren muss. Dies wurde behoben und ich hoffe, die Frage macht jetzt etwas mehr Sinn.)

Ich habe eine Liste von Objekten mit Punktzahlen und versuche, diesen Objekten basierend auf diesen Punktzahlen Ränge zuzuweisen. Unten ist im Grunde genommen, wie ich meine Daten ausgebe.

sorted_scores = [
    ('Apolo Ohno', 0),
    ('Shanie Davis', -1),
    ('Bodie Miller', -2),
    ('Lindsay Vohn', -3),  
    ('Shawn White', -3),
    ('Bryan Veloso', -4)
]

Ich habe ein Unentschieden. Die Funktion, die im Moment den Objekten Positionen zuweist, ist einfach eine Schleife, die den Wert von i als die endgültige Position des Objekts zuweist.

positions = {}

i = 1
for key, value in sorted_list:
    # Da in meinem Code die Zeichenfolgen IDs sind, verwende ich den Schlüssel, um das Objekt abzurufen.
    if value is not None:
        positions[key] = i
        i += 1

Das wird offensichtlich zurückgeben:

positions = {
    'Apolo Ohno': 1,
    'Shanie Davis': 2,
    'Bodie Miller': 3,
    'Lindsay Vohn': 4,        
    'Shawn White': 5,
    'Bryan Veloso': 6
}

Hoffentlich ergibt das etwas Sinn. Der Kern der Frage liegt in dieser Schleife. Es würde mehr Sinn ergeben, wenn sie sie wie folgt zurückgeben würde:

positions = {
    'Apolo Ohno': 1,
    'Shanie Davis': 2,
    'Bodie Miller': 3,
    'Lindsay Vohn': 4, # Gleicher Wert.
    'Shawn White': 4, # Gleicher Wert.
    'Bryan Veloso': 6
}

Wie würde ich die obige Funktion bearbeiten, um das zu erreichen, unter Berücksichtigung, dass ich zu einem beliebigen Zeitpunkt beliebig viele Gleichstände haben könnte, je nachdem, wie viele meiner Mitglieder das betreffende Objekt gerankt haben? Der höchste Rang sollte 1 sein, so dass er als solcher angezeigt werden kann: /

Vielen Dank im Voraus. :)

1voto

mstringer Punkte 2091

Hier ist ein Ansatz, der Aspekte einiger anderer Lösungen in eine flexible Generatorfunktion kombiniert.

def rang_sortiert(sequence, start=1, key=None, reverse=True):
    """Eine Kombination aus `enumerate` und `sorted` Iteratoren, die sich mit gebundenen Rängen befasst.

    """
    previous_value = object()  # wird nichts gleich machen
    sorted_iterator = sorted(sequence, key=key, reverse=reverse)
    for index, element in enumerate(sorted_iterator, start=start):

        # Verwendung der key-Funktion, um den Wert auszuwählen, falls angegeben
        if key is None:
            wert = element
        else:
            wert = key(element)

        # Rang nur aktualisieren, wenn sich der Sortiervorgang ändert
        if wert != previous_value:
            previous_value = wert
            rang = index

        yield rang, element

Sie können verschiedene Werte für start, key und reverse angeben, um Ränge zu ermöglichen, die bei 0 oder 1 beginnen, eine benutzerdefinierte Schlüsselfunktion zu übergeben (wie itemgetter(1) zum Sortieren von Wörterbüchern nach Wert) und einfach zu niedrigere Punktzahlen als höhere Ränge zu betrachten. Verwendung des Beispiels in der Originalfrage:

from operator import itemgetter

sortierte_scores = [
    ('Apolo Ohno', 0),
    ('Shanie Davis', -1),
    ('Bodie Miller', -2),
    ('Lindsay Vohn', -3),  
    ('Shawn White', -3),
    ('Bryan Veloso', -4)
]

höher_ist_besser = dict(
    (name, rang)
    for rang, (name, punktzahl)
    in rang_sortiert(sortierte_scores, key=itemgetter(1))
)
# {'Apolo Ohno': 1, 'Bryan Veloso': 6, 'Shanie Davis': 2, 'Lindsay Vohn': 4, 'Bodie Miller': 3, 'Shawn White': 4}

niedriger_ist_besser = dict(
    (name, rang)
    for rang, (name, punktzahl)
    in rang_sortiert(sortierte_scores, key=itemgetter(1), reverse=False)
)
# {'Apolo Ohno': 6, 'Bryan Veloso': 1, 'Shanie Davis': 5, 'Lindsay Vohn': 2, 'Bodie Miller': 4, 'Shawn White': 2}

1voto

Wie die beste Antwort, nur mit beibehalten der Ordnungszahlen anstelle des Überspringens zur nächsten Position in der Rangliste: d.h.: Rangliste = [1,2,3,4,4,5] anstelle von Rangliste = [1,2,3,4,4,6]

    sorted_scores = [
     ('Apolo Ohno', 0),
     ('Shanie Davis', -1),
     ('Bodie Miller', -2),
     ('Lindsay Vohn', -3),  
     ('Shawn White', -3),
     ('Bryan Veloso',-4)
]

res = {}
prev = None
n = 0 
for k,v in sorted_scores:
    if v!=prev:
        n +=1 
        place,prev = n,v
    res[k] = place

print (res)
{'Apolo Ohno': 1, 'Shanie Davis': 2, 'Bodie Miller': 3, 'Lindsay Vohn': 4, 'Shawn White': 4, 'Bryan Veloso': 5}

0voto

bignose Punkte 27108

Ich muss eine Menge Annahmen darüber treffen, was Sie tun möchten, aber hier ist ein Versuch:

scores = {
    'lorem': 100,
    'ipsum': 200,
    'dolor': 300,
    'sit': 300,
    'amet': 300,
    'quia': 400,
    'consectetur': 500,
    'adipiscing': 500,
    'elit': 600,
}

groups = {}
for (member, score) in scores.items():
    if score not in groups:
        groups[score] = [member]
    else:
        groups[score].append(member)

positions = {}
for (rank, (score, members)) in enumerate(groups.items()):
    for member in members:
        positions[member] = rank

Erweitert für Details, um die Funktionsweise anzuzeigen:

>>> import pprint
>>> scores = {
...     'lorem': 100,
...     'ipsum': 200,
...     'dolor': 300,
...     'sit': 300,
...     'amet': 300,
...     'quia': 400,
...     'consectetur': 500,
...     'adipiscing': 500,
...     'elit': 600,
... }
>>> groups = {}
>>> for (member, score) in scores.items():
...     if score not in groups:
...         groups[score] = [member]
...     else:
...         groups[score].append(member)
...
>>> pprint.pprint(groups)
{100: ['lorem'],
 200: ['ipsum'],
 300: ['sit', 'dolor', 'amet'],
 400: ['quia'],
 500: ['consectetur', 'adipiscing'],
 600: ['elit']}
>>> positions = {}
>>> for (rank, (score, members)) in enumerate(groups.items()):
...     for member in members:
...         positions[member] = rank
...
>>> pprint.pprint(positions)
{'adipiscing': 4,
 'amet': 2,
 'consectetur': 4,
 'dolor': 2,
 'elit': 5,
 'ipsum': 1,
 'lorem': 0,
 'quia': 3,
 'sit': 2}
>>> pprint.pprint(sorted(positions.items(), key=lambda i: i[1]))
[('lorem', 0),
 ('ipsum', 1),
 ('sit', 2),
 ('dolor', 2),
 ('amet', 2),
 ('quia', 3),
 ('consectetur', 4),
 ('adipiscing', 4),
 ('elit', 5)]

0voto

vishvananda Punkte 459

Hier ist eine einfache Möglichkeit, es zu tun

last = None
position = 0
delta = 1
for key, value in sorted_list:
    if value is not None:
        if value != last:
            position += delta
            delta = 1
        else:
            delta += 1
        # Ich glaube, dass dies im Code des OP [key] sein soll und nicht [value]
        positions[key] = position
        last = value

0voto

John La Rooy Punkte 278961
>>> sorted_scores = [
...     ('Apolo Ohno', 0),
...     ('Shanie Davis', -1),
...     ('Bodie Miller', -2),
...     ('Lindsay Vohn', -3),  
...     ('Shawn White', -3),
...     ('Bryan Veloso',-4)
... ]
>>> 
>>> from itertools import groupby
>>> from operator import itemgetter
>>> 
>>> place=1
>>> res={}
>>> for _,items in groupby(sorted_scores,key=itemgetter(1)):
...     for i,item in enumerate(items):
...         res[item[0]]= place
...     place+=i+1
... 
>>> print res
{'Apolo Ohno': 1, 'Bryan Veloso': 6, 'Shanie Davis': 2, 'Lindsay Vohn': 4, 'Bodie Miller': 3, 'Shawn White': 4}

Denken Sie daran, dass dicts ungeordnet sind. Um in der Reihenfolge des Platzes zu iterieren, müssen Sie dies tun

>>> print sorted(res.items(),key=itemgetter(1))
[('Apolo Ohno', 1), ('Shanie Davis', 2), ('Bodie Miller', 3), ('Lindsay Vohn', 4), ('Shawn White', 4), ('Bryan Veloso', 6)]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X