Seite 1 von 1

Element in Sequenz finden und rotieren

Verfasst: Donnerstag 27. September 2007, 05:58
von calo
Hallo,

ich bin mir nicht sicher ob es auch besser geht. Jedenfalls sieht meine Lösung ziemlich umständlich aus. Ziel ist es eine Sequenz (in meinem Fall: Tuple in Tuple) solange zu rotieren bis ein Wertepaar, dass mit einem bestimmten Wert beginnt, an erster Stelle steht. Das Tuple mit den Wertepaaren könnte folgendermaßen aussehen:

Code: Alles auswählen

nodepairs = ((23, 14),(12, 13),(982,27893),(1233,37),(1,8123))
Im Falle, dass 982 die gesuchte Nummer ist, soll das Ergebnis so aussehen:

Code: Alles auswählen

np = ((982,27893),(1233,37),(1,8123),(23, 14),(12, 13))
In der Praxis sind das mehrere Tausend Wertepaare. Keine Nummer wiederholt sich dabei. Meine bisherige Lösung dazu:

Code: Alles auswählen

import scipy

def rot(seq, n=1):
    """rotates and returns the sequence seq 
    """
    c = len(seq)
    if c == 0: return seq
    n = n % c
    return seq[n:] + seq[:n]

start_node = 982
start_pos = scipy.array(nodepairs).transpose().tolist()[0].index(start_node) + 1
np = rot(nodepairs, start_pos)
Meine Lösung funktioniert ja. Sieht aber unschön aus. Insbesondere Zeile 12. Darin wird das Wertepaar, dass mit start_node beginnt gesucht bzw dessen Index. Lässt sich diese Zeile auch irgendwie eleganter lösen?

Grüßle, Calo

Verfasst: Donnerstag 27. September 2007, 08:29
von Rebecca
Ich finde das hier besser:

Code: Alles auswählen

def rot(seq, search):
    for (i, item) in enumerate(seq):
        if item[0] == search: break
    else:
        raise ValueError("%s not in sequence." % search)

    return seq[i:] + seq[:i]

Code: Alles auswählen

>>> nodepairs = ((23, 14),(12, 13),(982,27893),(1233,37),(1,8123))
>>> rot(nodepairs, 982)
((982, 27893), (1233, 37), (1, 8123), (23, 14), (12, 13))
>>> rot(nodepairs, 14)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test.py", line 7, in rot
    raise ValueError("%s not in sequence." % search)
ValueError: 14 not in sequence.

Verfasst: Donnerstag 27. September 2007, 10:03
von BlackJack
Und noch eine Variante mit etwas generischerer `index()` und `rotated()` Funktionen:

Code: Alles auswählen

from itertools import imap
from operator import itemgetter


def index(iterable, needle, key=lambda x: x):
    for i, item in enumerate(imap(key, iterable)):
        if needle == item:
            return i
    raise ValueError('nothing found')


def rotated(sequence, amount=1):
    if not (sequence or amount):
        return sequence
    return sequence[amount:] + sequence[:amount]


def main():
    node_pairs = ((23, 14), (12, 13), (982, 27893), (1233, 37), (1, 8123))
    position = index(node_pairs, 982, itemgetter(0))
    node_pairs = rotated(node_pairs, position)
    print node_pairs

Verfasst: Donnerstag 27. September 2007, 11:57
von Y0Gi
Bei "rotieren" muss ich sofort an `collections.deque` denken, eine doppelt verkettete Liste mit schneller Rotationsoperation. Das kommt vielleicht für dich in Frage.

Verfasst: Donnerstag 27. September 2007, 16:10
von calo
Hallo,

vielen Dank für die Tipps :D

calo