2
votes

Indexation logique avec la carte de Python

TL DR: Comment puis-je utiliser au mieux map pour filtrer une liste basée sur une indexation logique?

Étant donné une liste:

['N/A']

Je voudrais mapper la fonction suivante et utiliser le résultat pour filtrer ma liste. Je pourrais le faire avec filter et d'autres méthodes, mais je cherche surtout à savoir si cela peut être fait uniquement en utilisant map .

La fonction: p >

values[[x for x in list(map(is_int, values)) if x is False]]

Tentative de solution:

[values[x] for x  in list(map(is_int, values)) if x is False]

Ce qui précède me donne les valeurs dont j'ai besoin. Cependant, il ne renvoie pas l'index ni n'autorise l'indexation logique. J'ai essayé de faire d'autres choses ridicules comme:

[x for x in list(map(is_int, values)) if x is False]

et bien d'autres qui ne fonctionnent évidemment pas.

Ce que je pensais pouvoir faire:

def is_int(val):
    try:
        x = int(val)
        return True
    except ValueError:
        return False

Résultat attendu :

values = ['1', '2', '3', '5', 'N/A', '5']


3 commentaires

Vous ne pouvez pas utiliser map () seul pour effectuer une réduction. De par sa définition même, map () préserve le nombre d’éléments en.wikipedia.org/wiki/Map_ (fonction d'ordre supérieur) . D'un autre côté, les opérations de réduction sont censées faire ce que vous voulez. En Python, ils peuvent être implémentés normalement avec une expression de générateur ou pour les programmeurs plus fonctionnels, avec filter () . D'autres approches non primitives peuvent exister, mais elles se résument essentiellement à l'une des deux.


Merci, je voulais en fait utiliser le résultat de map comme ceci: values ​​[result of map] pour renvoyer le résultat pas littéralement utiliser map pour filtre.


Oh OK, c'est un peu différent alors. Regardez ma réponse.


6 Réponses :


5
votes
[v for v, b in zip(values, [is_int(x) for x in values]) if not b]

4 commentaires

Merci, existe-t-il un moyen d'utiliser la carte ? Je demande surtout à savoir à quel point la map est flexible depuis que je suis nouveau dans python . Sinon, pourquoi ne pouvons-nous pas utiliser map ici? Désolé si c'est trop large.


@NelsonGon En Python, les les compréhensions de listes sont généralement préférées aux cartes s ; si vous êtes nouveau dans Python, je vous encourage à «continuer» même si d'autres langages préfèrent une construction de type map. (Il devrait cependant y avoir un moyen de passer par map .)


Merci @Leporello je m'habituerai alors aux compréhensions.


Ou [v pour v, b dans zip (valeurs, map (is_int, valeurs)) sinon b] .



4
votes

vous pouvez obtenir le résultat attendu en utilisant le simple extrait de code écrit ci-dessous qui n'implique aucune fonction de carte

[values[i] for i,y in enumerate(list(map(is_int,values))) if y is False]

Et, si vous souhaitez utiliser strictement la fonction map alors l'extrait ci-dessous vous aidera

[x for x in values if is_int(x) is False]


3 commentaires

Ah, je viens de penser à utiliser enumerate en ce moment. Cette dernière solution est-elle efficace en termes de calcul?


Oui, énumérer sera l'outil le plus simple et le plus utile pour cette question


En quoi enumerate est-il plus simple qu'une simple compréhension de liste? Aussi, mieux vaut faire sinon x au lieu de si x est faux . En outre, vous pouvez énumérer la carte directement, sans avoir besoin de liste .



1
votes

map n'est tout simplement pas le bon outil pour le travail, car cela transformerait les valeurs, alors que vous voulez simplement les vérifier. Si quoi que ce soit, vous recherchez un filtre , mais vous devez d'abord "inverser" la fonction de filtre:

>>> values = ['1', '2', "foo", '3', '5', 'N/A', '5']                       
>>> not_an_int = lambda x: not is_int(x)                                   
>>> list(filter(not_an_int, values))                                       
['foo', 'N/A']

En pratique, cependant, je préfère utiliser un compréhension de liste avec une condition.


0 commentaires

1
votes

Vous pouvez le faire en utilisant un peu d'aide de itertools et en annulant la sortie de votre fonction d'origine car nous voulons qu'elle renvoie True là où ce n'est pas un entier .

from itertools import compress
from operator import not_

list(compress(values, map(not_, map(is_int, values))))

['N/A']


0 commentaires

1
votes

3 commentaires

La solution numpy est superbe. J'ai malheureusement déjà accepté une réponse (je n'aime pas désaccepter si c'est un mot) mais merci.


Ne devrait-il pas être pas is_int (x) dans le premier filtre ? Il vous manque le (x) .


@tobias_k Oui, désolé, il a simplement disparu lors de la frappe. Merci de l'avoir repéré.



0
votes

Pas exactement ce que j'avais à l'esprit, mais quelque chose que j'ai appris de ce problème, nous pourrions faire ce qui suit (ce qui pourrait être moins efficace en termes de calcul). C'est presque similaire à la réponse de @aws_apprentice. De toute évidence, il vaut mieux utiliser le filtre et / ou la compréhension de liste:

from itertools import compress
list(compress(values, map(lambda x: not is_int(x), values)))

Ou comme suggéré par @aws_apprentice simplement:

from itertools import compress
list(compress(values, list(map(lambda x: not is_int(x), values))))


2 commentaires

vous n'avez pas besoin de l'appel intermédiaire à list , l'objet map seul suffira


Oh woow, merci. J'ai vraiment un long chemin à parcourir mais j'ai trouvé cette fonctionnalité intéressante.