`elif` em condicionais de compreensão de lista

128

Podemos usar elifna compreensão de listas?

Exemplo:

l = [1, 2, 3, 4, 5]

for values in l:
    if values==1:
        print 'yes'
    elif values==2:
        print 'no'
    else:
        print 'idle'

Podemos incluir o elifem nossa lista de compreensão, de maneira semelhante ao código acima?

Por exemplo, uma resposta como:

['yes', 'no', 'idle', 'idle', 'idle']

Até agora, eu só usei ife elsena compreensão de listas.

auto
fonte

Respostas:

249

As expressões condicionais do Python foram projetadas exatamente para este tipo de caso de uso:

>>> l = [1, 2, 3, 4, 5]
>>> ['yes' if v == 1 else 'no' if v == 2 else 'idle' for v in l]
['yes', 'no', 'idle', 'idle', 'idle']

Espero que isto ajude :-)

Raymond Hettinger
fonte
5
Há uma história interessante na sintaxe. Por muitos anos, antes de sua introdução, "expressões terciárias" foram uma das cinco mudanças mais solicitadas na linguagem. Visto que Guido van Rossum a projetou explicitamente como uma linguagem baseada em declarações, ele resistiu firmemente por um longo tempo (expressões terciárias, e particularmente seu abuso, são fontes de muita obscuridade no código). Quando finalmente sucumbiu, anunciou que havia escolhido deliberadamente uma sintaxe que desencorajava o uso excessivo. Como sempre, ele fez um trabalho de design elegante.
holdenweb
1
Ternário, droga (escreveu ele, percebendo seu erro disléxico tarde demais para editar).
holdenweb
2
Enquanto eu voto a favor dessa resposta, quero mencionar o seguinte: para 1 par de if / else é fácil de ler, 2 pares: está ficando mais difícil de entender. Nem mencione 3 pares. Se a expressão precisar de 3 ou mais pares, um dicionário ou uma função separada tornará as coisas mais fáceis de ler e entender.
Hai Vu
1
Eu gostaria de adicionar não uma solução para este problema, mas um lembrete de código limpo: uma vez que essa compreensão de lista tem três condicionais, provavelmente poderia ser refatorada em um método mais descritivo. Meu ponto é este: martinfowler.com/bliki/FunctionLength.html :)
Alvaro Cavalcanti
Me deparei com um caso em que precisava de um elif, mas apenas dois valores. Usando este exemplo, eu precisaria apenas ['yes', 'no']ser feito. Para fazer isso, você pode fazer: ['yes' if v == 1 else 'no' for v in l if values in [1,2]]. Atualmente, não consigo pensar em uma maneira mais limpa de fazer isso.
dTanMan
48
>>> d = {1: 'yes', 2: 'no'}
>>> [d.get(x, 'idle') for x in l]
['yes', 'no', 'idle', 'idle', 'idle']
Ignacio Vazquez-Abrams
fonte
4
Acho que esta forma é muito mais fácil de digerir do que tentar fazer uma lógica if / else realmente longa e complicada dentro da lista comp
jdi
5
@jdi Embora as expressões-condicionais possam não ser do seu gosto, elas foram projetadas especificamente para lidar com cadeias if-elif-elif-else, assim como o OP solicitou. Eles não são difíceis de aprender e pode graciosamente lidar com situações que não são tão passíveis de lógica pesquisa de dicionário: 'A' if grade>=90 else 'B' if grade>=80 else 'C' if grade>=70 else 'F'.
Raymond Hettinger,
1
Existe uma vantagem em definir dfora da compreensão?
Chris_Rands
O motivo pelo qual gosto mais da compreensão da lista é que ela é lida exatamente como o inglês. Mesmo um não programador seria capaz de entender o que ele faz. Com esta solução, você deve entender o método dict.get ().
Tim Skov Jacobsen
25

Você pode, mais ou menos.

Observe que quando você usa o sytax como:

['yes' if v == 1 else 'no' for v in l]

Você está usando a forma ternária do operador if / else (se estiver familiarizado com linguagens como C, é como a ?:construção (v == 1 ? 'yes' : 'no'):).

A forma ternária do operador if / else não tem um 'elif' embutido, mas você pode simulá-lo na condição 'else':

['yes' if v == 1 else 'no' if v == 2 else 'idle' for v in l]

É como dizer:

for v in l:
    if v == 1 :
        print 'yes'
    else:
        if v == 2:
            print 'no'
        else:
            print 'idle'

Portanto, não há uma construção 'elif' direta como você perguntou, mas pode ser simulada com instruções if / else aninhadas.

café matemático
fonte
O código do último parágrafo é muito perspicaz, obrigado!
devianceee
3

Talvez você queira isto:

l = [1, 2, 3, 4, 5] 

print ([['idle','no','yes'][2*(n==1)+(n==2)] for n in l])
Ratnesh Kushwaha
fonte
2

Você pode usar a compreensão de lista se for criar outra lista a partir do original.

>>> l = [1, 2, 3, 4, 5]
>>> result_map = {1: 'yes', 2: 'no'}
>>> [result_map[x] if x in result_map else 'idle' for x in l]
['yes', 'no', 'idle', 'idle', 'idle']
San4ez
fonte
2

Outra maneira fácil é usar a compreensão de lista condicional como esta:

l=[1,2,3,4,5]
print [[["no","yes"][v==1],"idle"][v!=1 and v!=2] for v in l]

fornece a resposta correta:

['sim', 'não', 'ocioso', 'ocioso', 'ocioso']

Stefan Gruenwald
fonte