web-dev-qa-db-fra.com

Comment obtenir l'index d'un entier d'une liste si la liste contient un booléen?

Je commence juste avec Python.

Comment obtenir un index de nombre entier 1 à partir d'une liste si la liste contient un objet booléen True avant le 1?

>>> lst = [True, False, 1, 3]
>>> lst.index(1)
0
>>> lst.index(True)
0
>>> lst.index(0)
1

Je pense que Python considère 0 comme False et 1 comme True dans l'argument de la méthode index. Comment puis-je obtenir l'index de nombre entier 1 (c'est-à-dire 2)?

Aussi, quel est le raisonnement ou la logique derrière le traitement d'objet booléen de cette façon dans la liste? En ce qui concerne les solutions, je peux voir que ce n’est pas si simple.

14

La documentation dit que 

Les listes sont des séquences modifiables, généralement utilisées pour stocker des collections de Éléments homogènes (où le degré de similarité précis variera en fonction de Application).

Vous ne devez pas stocker de données hétérogènes dans des listes. L'implémentation de list.index effectue uniquement la comparaison à l'aide de Py_EQ (opérateur ==). Dans votre cas, cette comparaison retourne une valeur de vérité car True et False ont respectivement les valeurs des entiers 1 et 0 ( la classe bool est une sous-classe de int après tout).

Cependant, vous pouvez utiliser l'expression du générateur et la fonction _next intégrée (pour obtenir la première valeur du générateur) comme ceci:

In [4]: next(i for i, x in enumerate(lst) if not isinstance(x, bool) and x == 1)
Out[4]: 2

Ici, nous vérifions si x est une instance de bool before en comparant x à 1. 

Gardez à l'esprit que next peut augmenter StopIteration, dans ce cas, il peut être souhaitable de (re) lever ValueError (pour imiter le comportement de list.index).

Envelopper tout cela dans une fonction:

def index_same_type(it, val):
    gen = (i for i, x in enumerate(it) if type(x) is type(val) and x == val)
    try:
        return next(gen)
    except StopIteration:
        raise ValueError('{!r} is not in iterable'.format(val)) from None

Quelques exemples:

In [34]: index_same_type(lst, 1)
Out[34]: 2

In [35]: index_same_type(lst, True)
Out[35]: 0

In [37]: index_same_type(lst, 42)
ValueError: 42 is not in iterable
13
vaultah

Les booléens sont entiers en Python, et c'est pourquoi vous pouvez les utiliser comme n'importe quel entier:

>>> 1 + True
2
>>> [1][False]
1

[Cela ne signifie pas que vous devriez :)]

Ceci est dû au fait que bool est une sous-classe de int, et presque toujours un booléen se comportera comme 0 ou 1 (sauf s'il est converti en chaîne - vous obtiendrez plutôt "False" et "True").

Voici une autre idée de la manière dont vous pouvez réaliser ce que vous voulez (essayez toutefois de repenser votre logique en tenant compte des informations ci-dessus):

>>> class force_int(int):
...     def __eq__(self, other):
...         return int(self) == other and not isinstance(other, bool)
... 
>>> force_int(1) == True
False
>>> lst.index(force_int(1))
2

Ce code redéfinit la méthode int, utilisée pour comparer les éléments de la méthode index, pour ignorer les booléens.

8
Roman Bodnarchuk

Voici une solution simple et naïve à un seul support utilisant map et Zip :

>>> Zip(map(type, lst), lst).index((int, 1))
2

Ici, nous mappons le type de chaque élément et créons une nouvelle liste en compressant les types avec les éléments et demandons l'index de (type, value).

Et voici une solution itérative générique utilisant la même technique:

>>> from itertools import imap, izip
>>> def index(xs, x):
...     it = (i for i, (t, e) in enumerate(izip(imap(type, xs), xs)) if (t, e) == x)
...     try:
...             return next(it)
...     except StopIteration:
...             raise ValueError(x)
... 
>>> index(lst, (int, 1))
2

Ici, nous faisons essentiellement le même chose mais de manière itérative afin de ne pas nous coûter cher en termes d’efficacité mémoire/espace. Nous sommes un itérateur de la même expression que ci-dessus mais en utilisant imap et izip et créons une fonction d'index personnalisée qui renvoie la valeur suivante de l'itérateur ou une augmentation de ValueError s'il n'y a pas de correspondance.

5
James Mills

Essayez ceci.

for i, j in enumerate([True, False, 1, 3]):
    if not isinstance(j, bool) and j == 1:
        print i

Sortie:

2
0
Haresh Shyara