2015-04-30 8 views
5

Ich habe ein Problem, das ist: ein Tupel mit Objekten aller Art zu erhalten, und trennen Sie es in zwei Tupel: das erste, nur mit Strings; die zweite, nur mit Zahlen.Wie teilt man ein Tupel in zwei in pythonischer Weise

In Ordnung. Der Standard-Algorithmus wäre so etwas wie:

def separate(input_tuple): 
    return_tuple = ([],[]) 
    for value in input_tuple: 
     if isinstance(value, str): 
      return_tuple[0].append(value) 
     if isinstance(value, numbers.Number): 
      return_tuple[1].append(value) 
    return tuple([tuple(l) for l in return_tuple]) 

Auf diese Weise wir iterieren nur einmal.

Meine Frage ist: Gibt es einen Weg, es auf eine pythischere Weise zu tun? Ein Einliner?

Ich habe

versucht
(tuple([i for i in input_tuple if isinstance(i,str)]), tuple([i for i in input_tuple if isinstance(i,numbers.Number)])) 

Aber es ist weniger effizient, da wir zweimal über den Eingangstupel laufen. Auch

,

tuple([ tuple([i for i in input_tuple if isinstance(i, k)]) for k in ((float ,int,complex), str) ]) 

hat das gleiche Problem, wie wir zwei Iterationen tun. Wäre es möglich, nur einmal zu iterieren und trotzdem das Ergebnis zu erhalten, oder weil es sich um eine Trennung in zwei Tupel handelt, ist das nicht möglich?

Danke!

+3

Gehen Sie nicht auf den "pythonischen Weg", es ist ein Fallstrick, der nichts nützt und fast immer ein ziemlich lesbares und leicht zu verstehendes Stück Code in ein 1-Zeilen-Decoder-Ring-Chaos verwandelt. Ihr Ziel sollte es sein, den Code in einem Format zu formatieren, das leicht zu pflegen und zu lesen ist und nicht so wenige Zeilen wie möglich zu haben. –

+0

@TymoteuszPaul Ich bin mir dessen bewusst. Ich benutze diesen Code nicht wirklich, aber ich fühle mich eingeschränkt, wenn ich über Listenverstehen nachdenke, und ich habe das in letzter Zeit studiert; Leute vom Stapelüberlauf beeindrucken mich immer mit ihren Antworten, deshalb frage ich mich, ob das möglich ist! Aber danke für den Rat! Schließlich ist "Explizit ist besser als implizit"! – RafaelC

+1

In Java nennen wir diese Prozessversplitterung liebevoll! spliterators ftw. – Shashank

Antwort

3

Ich nehme an, Sie so etwas wie

my_tuple = ([],[]) 
for x in a_list: 
    my_tuple[isinstance(x,basestring)].append(x) 

tun könnte, dass es ein wenig mehr pythonic würde ich raten ... und immer noch ziemlich lesbar.

Natürlich können Sie auch in einer Liste Verständnis setzen es aber nicht ein großer:

[my_tuple[isinstance(x,basestring)].append(x) for x in a_list] 

Die Liste Verständnis wird nur weggeworfen und seine im Grunde in eine for-Schleife missbraucht wird.

+0

Sehr, sehr, sehr nette Art, wie du da hingekommen bist! Ich freue mich sehr über deine Antwort! Die Verwendung der 'bool'-Rendite als Index war etwas, was ich niemals denken würde. Ich danke dir sehr! – RafaelC

+0

Wie würden Sie mit seinen * "Objekten jeglicher Art" * umgehen? Ihr Code fügt Listen, Mengen usw. in das Zahlentupel ein. –

+1

True Dies ist eine sehr binäre Lösung, in der alle Elemente der Liste in eine von zwei Bins sortiert sind ... was mein Lesen der ursprünglichen Problemaussage erfüllt, also werde ich einfach diese einfachen Sortierungen in Strings und Non-Strings sagen kann oder darf nicht ausreichen) –

0

Versuchen Sie dieses:

tuple(list(filter(lambda e: isinstance(e, t), input_tuple)) for t in (str,int)) 
+0

sehr schlau .... leider ist es noch zweimal iterieren :) aber das ist eine coole Antwort denke ich (+1) –

+0

Wirklich schöne Alternative! Wie Joran sagte, ist es jedoch doppelt so lang wie meine Codes! – RafaelC

+0

Obwohl der Code geschätzt wird, sollte es immer eine begleitende Erklärung haben. Dies muss nicht lange dauern, aber es wird erwartet. – peterh

2

Es ist kein Einzeiler, und es ist nicht einmal gleichwertig, was Sie anfangs taten, aber man kann einen Container von Listen verwenden, um ein „Mapping“ -Funktion zur Verfügung zu stellen:

>>> from numbers import Number 
>>> tup = (1, '2', 3, '4', 5) 
>>> di = {} 
>>> for x in tup: 
...  di.setdefault(Number if isinstance(x, Number) else str if isinstance(x, str) else object, []).append(x) 
... 
>>> di[str], di[Number] 
(['2', '4'], [1, 3, 5]) 

Wie @PadraicCunningham in den Kommentaren darauf hingewiesen hat, für Python 2, können Sie basestring statt str zu Unicode-Typen zu erfassen.

+0

Dies würde brechen, sobald Sie einen nicht-int oder str –

+0

@PadraicCunningham Fixed treffen, um es unzerbrechlich zu machen. – Shashank

+0

Ja, aber Sie werden am Ende alle Schwimmer, etc. fehlen. –

Verwandte Themen