Is er een manier om een ​​item in een tuple te vinden zonder een for-lus in Python te gebruiken?

Ik heb een tuple van waarden voor Controle en ik wil die met een overeenkomende naam vinden. Op dit moment gebruik ik dit:

listView
for control in controls:
    if control.name == "ListView":
        listView = control

Kan ik het eenvoudiger dan dit doen? Misschien iets als:

listView = controls.FirstOrDefault(c => c.name == "ListView")
5

3 antwoord

Hier is een optie:

listView = next(c for c in controls if c.name == "ListView")

Merk op dat dit een StopIteration oplevert als er geen overeenkomend item bestaat, dus je moet dit in een try/except plaatsen en vervangen door een standaard als je een StopIteration krijgt .

U kunt ook uw standaardwaarde toevoegen aan de iterabele zodat de aanroep volgende altijd slaagt.

from itertools import chain
listView = next(chain((c for c in controls if c.name == "ListView"), [default])

Als u Python 2.5 of lager gebruikt, wijzigt u de oproep van volgende (iterable) in iterable.next() .

6
toegevoegd

Uit pure nieuwsgierigheid heb ik mijn eigen antwoord geïntegreerd met je originele code en F.J.'s oplossingen om een ​​vergelijkende prestatietest te maken.

Het lijkt erop dat jouw oplossing de snelste is van allemaal. Mijn oplossing controleert alle mogelijke elementen van de besturingselementen tuple, dus het zal langzamer zijn naarmate de grootte van het tuple toeneemt.

Hier is de code:

from timeit import Timer as T
from itertools import chain, dropwhile

class control(object):
    def __init__(self, name):
        self.name = name

def johan_venge(tuple_):
    for el in tuple_:
        if el.name == 'foobar':
            return el
    return None

def mac(tuple_):
    return filter(lambda x : x.name == 'foobar', tuple_)[0]

def mac2(tuple_):
    return list(dropwhile(lambda x : x.name != 'foobar', tuple_))[0]

def fj(tuple_):
    return next(c for c in tuple_ if c.name == 'foobar')

def fj2(tuple_):
    return next(chain((c for c in tuple_ if c.name == 'foobar')))

if __name__ == '__main__':
    REPS = 10000
    controls = (control('hello'), control('world'), control('foobar'))
    print T(lambda : johan_venge(controls)).repeat(number = REPS)
    print T(lambda : mac(controls)).repeat(number = REPS)
    print T(lambda : mac2(controls)).repeat(number = REPS)
    print T(lambda : fj(controls)).repeat(number = REPS)
    print T(lambda : fj2(controls)).repeat(number = REPS)    

en hier is de uitvoer op mijn systeem:

[0.005961179733276367, 0.005975961685180664, 0.005918025970458984]
[0.013427019119262695, 0.013586044311523438, 0.013450145721435547]
[0.024325847625732422, 0.0254058837890625, 0.02396702766418457]
[0.014491081237792969, 0.01442408561706543, 0.01484990119934082]
[0.01691603660583496, 0.016616106033325195, 0.016437053680419922]

HTH! :)

2
toegevoegd
Bedankt voor deze test. Tussen haakjes, ik weet niet zeker hoe ik de uitvoer moet interpreteren: O Je hebt resultaten naast elkaar voor dezelfde methode, maar verschillende resultaten voor elk, regel voor regel?
toegevoegd de auteur Joan Venge, de bron
Bedankt mac, nu is het logisch. Dit is waarschijnlijk eenvoudig, maar ik merkte dat je ' gebruikte, maar andere antwoorden gebruiken ", is er een verschil?
toegevoegd de auteur Joan Venge, de bron
Ik ben het ermee eens dat het er minder rommelig uitziet: O
toegevoegd de auteur Joan Venge, de bron
@JoanVenge - Bekijk de documentatie voor timeit.Timer .repeat . In principe zijn het drie runs van 10.000 iteratie voor elke oplossing.
toegevoegd de auteur mac, de bron
@JoanVenge - Nee, ik vind het gewoon minder mijn code klemmen ...
toegevoegd de auteur mac, de bron
listView = filter(lambda c: c.name=="ListView", controls)[0]

Gooit IndexError als er geen dergelijke controle bestaat.

Een beetje esoterisch, maar zonder try/except:

listView = (lambda x: x[0] if x else None)(filter(lambda c: c.name=="ListView", controls))
1
toegevoegd
Kan dit worden aangepast als FJ's antwoord, zodat het geen uitzondering oplevert zonder try/catch te gebruiken? Gewoon nieuwsgierig.
toegevoegd de auteur Joan Venge, de bron
Bedankt mac, zeer goede tip.
toegevoegd de auteur Joan Venge, de bron
:-) meer tekens (-:
toegevoegd de auteur nisc, de bron
Ik heb mijn antwoord bijgewerkt met mijn suggestie ;-)
toegevoegd de auteur nisc, de bron
We hebben in principe dezelfde oplossing tegelijkertijd gepost! Controleer mijn antwoord als je geïnteresseerd bent om te zien hoe snel het is in vergelijking met de anderen! :)
toegevoegd de auteur mac, de bron
@JoanVenge - U kunt als u het in twee regels splitst: eerste regel filt = filter (... alleen.) Tweede regel: return filt [0] als len (gefilterd)> 0 anders geen .
toegevoegd de auteur mac, de bron