Je veux obtenir les valeurs uniques de la liste suivante:
[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
La sortie dont j'ai besoin est:
[u'nowplaying', u'PBS', u'job', u'debate', u'thenandnow']
Ce code fonctionne:
output = []
for x in trends:
if x not in output:
output.append(x)
print output
y a-t-il une meilleure solution que je devrais utiliser?
Commencez par déclarer votre liste correctement, en les séparant par une virgule. Vous pouvez obtenir les valeurs uniques en convertissant la liste en un ensemble.
mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
myset = set(mylist)
print(myset)
Si vous l'utilisez encore comme liste, vous devriez le reconvertir en faisant ceci:
mynewlist = list(myset)
Une autre possibilité, probablement plus rapide, serait d'utiliser un ensemble depuis le début, au lieu d'une liste. Ensuite, votre code devrait être:
output = set()
for x in trends:
output.add(x)
print(output)
Comme il a été souligné, les ensembles ne conservent pas l'ordre d'origine. Si vous en avez besoin, vous devriez vous renseigner sur le ensemble ordonné .
Pour être cohérent avec le type que j'utiliserais:
mylist = list(set(mylist))
quel type est votre variable de sortie?
Python sets sont ce dont vous avez juste besoin. Déclarez la sortie comme ceci:
output = set([]) # initialize an empty set
et vous êtes prêt à ajouter des éléments avec output.add(elem)
et assurez-vous qu'ils sont uniques.
Attention: les ensembles ne conservent pas l'ordre d'origine de la liste.
Si nous devons garder l'ordre des éléments, que diriez-vous de ceci:
_used = set()
mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = [x for x in mylist if x not in used and (used.add(x) or True)]
_
Et encore une solution utilisant reduce
et sans le temporaire used
var.
_mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])
_
MISE À JOUR - Mars 2019
Et une troisième solution, qui est nette, mais assez lente puisque _.index
_ est O (n).
_mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = [x for i, x in enumerate(mylist) if i == mylist.index(x)]
_
UPDATE - Oct, 2016
Une autre solution avec reduce
, mais cette fois sans _.append
_, ce qui la rend plus lisible par l'homme et plus facile à comprendre.
_mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])
#which can also be writed as:
unique = reduce(lambda l, x: l if x in l else l+[x], mylist, [])
_
NOTE: N'oubliez pas que plus le script est lisible par l'homme, plus le script est peu performant.
_import timeit
setup = "mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']"
#10x to Michael for pointing out that we can get faster with set()
timeit.timeit('[x for x in mylist if x not in used and (used.add(x) or True)]', setup='used = set();'+setup)
0.4188511371612549
timeit.timeit('[x for x in mylist if x not in used and (used.append(x) or True)]', setup='used = [];'+setup)
0.6157128810882568
timeit.timeit('reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])', setup=setup)
1.8778090476989746
timeit.timeit('reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])', setup=setup)
2.13108491897583
timeit.timeit('reduce(lambda l, x: l if x in l else l+[x], mylist, [])', setup=setup)
2.207760810852051
timeit.timeit('[x for i, x in enumerate(mylist) if i == mylist.index(x)]', setup=setup)
2.3621110916137695
_
RÉPONSE AUX COMMENTAIRES
Parce que @ monica a posé une bonne question sur "comment cela fonctionne-t-il?". Pour tout le monde ayant des problèmes pour le comprendre. Je vais essayer de donner une explication plus profonde sur la façon dont cela fonctionne et sur la sorcellerie qui se passe ici;)
Alors elle a d'abord demandé:
J'essaie de comprendre pourquoi
unique = [used.append(x) for x in mylist if x not in used]
ne fonctionne pas.
Eh bien ça marche
_>>> used = []
>>> mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
>>> unique = [used.append(x) for x in mylist if x not in used]
>>> print used
[u'nowplaying', u'PBS', u'job', u'debate', u'thenandnow']
>>> print unique
[None, None, None, None, None]
_
Le problème est que nous n'obtenons tout simplement pas les résultats souhaités dans la variable unique
, mais uniquement dans la variable used
. En effet, lors de la compréhension de la liste, _.append
_ modifie la variable used
et renvoie None
.
Donc, pour obtenir les résultats dans la variable unique
et continuer à utiliser la même logique avec .append(x) if x not in used
, nous devons déplacer cet appel _.append
_ à droite de la liste compréhension et simplement retourne x
du côté gauche.
Mais si nous sommes trop naïfs et allons simplement avec:
_>>> unique = [x for x in mylist if x not in used and used.append(x)]
>>> print unique
[]
_
Nous n'obtiendrons rien en retour.
Encore une fois, cela est dû au fait que la méthode _.append
_ renvoie None
, ce qui donne à notre expression logique l'aspect suivant:
_x not in used and None
_
Ce sera essentiellement toujours:
False
lorsque x
est dans used
,None
lorsque x
n'est pas dans used
.Et dans les deux cas (False
/None
), cela sera traité comme une valeur falsy
et nous obtiendrons une liste vide.
Mais pourquoi ceci est évalué à None
alors que x
n'est pas dans used
? Quelqu'un peut demander.
C'est parce que c'est comme ça que Python fonctionne court-circuit opérateurs fonctionne .
L'expression _
x and y
_ évalue d'abord x; si x est faux, sa valeur est renvoyée; sinon, y est évalué et la valeur résultante est renvoyée.
Ainsi, lorsque x
n’est pas utilisé (c’est-à-dire lorsque sa True
) la partie suivante ou l’expression sera évaluée ( used.append(x)
) et sa valeur (None
) seront renvoyés.
Mais c’est ce que nous voulons pour obtenir les éléments uniques d’une liste avec des doublons, nous voulons les _.append
_ dans une nouvelle liste uniquement lorsqu’ils sont arrivés pour la première fois.
Donc, nous voulons vraiment évaluer used.append(x)
uniquement lorsque x
n'est pas dans used
, peut-être s'il existe un moyen de transformer cette valeur None
en une valeur truthy
nous irons bien, non?
Eh bien oui et c’est ici que le 2e type d’opérateurs _short-circuit
_ vient jouer.
L'expression _
x or y
_ évalue d'abord x; si x est vrai, sa valeur est renvoyée; sinon, y est évalué et la valeur résultante est renvoyée.
Nous savons que .append(x)
sera toujours falsy
, donc si nous ajoutons juste un or
à ses côtés, nous aurons toujours la partie suivante. C'est pourquoi nous écrivons:
_x not in used and (used.append(x) or True)
_
afin que nous puissions évaluer used.append(x)
et obtenir True
en conséquence, uniquement lorsque la première partie de l'expression (x not in used)
est True
.
Une approche similaire peut être observée dans la deuxième approche avec la méthode reduce
.
_(l.append(x) or l) if x not in l else l
#similar as the above, but maybe more readable
#we return l unchanged when x is in l
#we append x to l and return l when x is not in l
l if x in l else (l.append(x) or l)
_
où nous:
x
à l
et renvoyez _ l
lorsque x
ne figure pas dans l
. Grâce à l'instruction or
, _.append
_ est évalué et l
est renvoyé par la suite.l
intacte lorsque x
est dans l
L'exemple que vous avez fourni ne correspond pas aux listes en Python. Cela ressemble à un dict imbriqué, ce qui n’est probablement pas ce que vous vouliez.
Une liste Python:
a = ['a', 'b', 'c', 'd', 'b']
Pour obtenir des objets uniques, transformez-le simplement en un ensemble (que vous pourrez reconvertir ultérieurement en liste si nécessaire):
b = set(a)
print b
>>> set(['a', 'b', 'c', 'd'])
Maintien de l'ordre:
# oneliners
# slow -> . --- 14.417 seconds ---
[x for i, x in enumerate(array) if x not in array[0:i]]
# fast -> . --- 0.0378 seconds ---
[x for i, x in enumerate(array) if array.index(x) == i]
# multiple lines
# fastest -> --- 0.012 seconds ---
uniq = []
[uniq.append(x) for x in array if x not in uniq]
uniq
L'ordre n'a pas d'importance:
# fastest-est -> --- 0.0035 seconds ---
list(set(array))
C'est une solution simple
list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
list=set(list)
Obtenir des éléments uniques de la liste
mylist = [1,2,3,4,5,6,6,7,7,8,8,9,9,10]
Utilisation de la logique simple à partir d'ensembles - Les ensembles sont une liste unique d'éléments
mylist=list(set(mylist))
In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Utiliser la logique simple
newList=[]
for i in mylist:
if i not in newList:
newList.append(i)
In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Utiliser la méthode pop -> pop supprime le dernier élément indexé et l’affiche à l’utilisateur. vidéo
k=0
while k < len(mylist):
if mylist[k] in mylist[k+1:]:
mylist.pop(mylist[k])
else:
k=k+1
In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Utiliser Numpy
import numpy as np
np.unique(mylist)
In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
set - collection non ordonnée d'éléments uniques. La liste des éléments peut être passée au constructeur de set. Donc, liste de passage avec des éléments en double, nous obtenons des éléments uniques et le transformons en liste puis nous obtenons une liste avec des éléments uniques. Je ne peux rien dire sur les performances et la surcharge de mémoire, mais j'espère que ce n'est pas si important avec les petites listes.
list(set(my_not_unique_list))
Simplement et court.
Si vous utilisez numpy dans votre code (ce qui pourrait être un bon choix pour de plus grandes quantités de données), vérifiez numpy.unique :
>>> import numpy as np
>>> wordsList = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
>>> np.unique(wordsList)
array([u'PBS', u'debate', u'job', u'nowplaying', u'thenandnow'],
dtype='<U10')
( http://docs.scipy.org/doc/numpy/reference/generated/numpy.unique.html )
Comme vous pouvez le constater, numpy prend en charge non seulement les données numériques, mais également les tableaux de chaînes. Bien sûr, le résultat est un tableau numpy, mais cela n'a pas beaucoup d'importance, car il se comporte toujours comme une séquence:
>>> for Word in np.unique(wordsList):
... print Word
...
PBS
debate
job
nowplaying
thenandnow
Si vous voulez vraiment avoir une liste Vanilla python, vous pouvez toujours appeler list ().
Cependant, le résultat est automatiquement trié, comme le montrent les fragments de code ci-dessus. Départ numpy unique sans tri si le maintien de l'ordre de la liste est requis.
Voici un résumé sur l'obtention d'éléments uniques, non ordonnés ou ordonnés.
Étant donné
from collections import OrderedDict
seq = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
Code
# Unordered
list(set(seq))
# Out: ['thenandnow', 'PBS', 'debate', 'job', 'nowplaying']
# Order-preserving
list(OrderedDict.fromkeys(seq))
# Out: ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']
Sinon, dans Python 3.6+:
# Order-preserving
list(dict.fromkeys(seq))
# Out: ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']
Remarque: les éléments listés doivent être hashable . Voir aussi les détails sur ce dernier exemple dans ce article de blog . En outre, voir post de R. Hettinger sur la même technique; l'ordre de préservation dict est étendu à partir de l'une de ses premières applications.
Liste unique du même ordre utilisant uniquement une compression de liste.
> my_list = [1, 2, 1, 3, 2, 4, 3, 5, 4, 3, 2, 3, 1]
> unique_list = [
> e
> for i, e in enumerate(my_list)
> if my_list.index(e) == i
> ]
> unique_list
[1, 2, 3, 4, 5]
enumerates
donne l'indice i
et l'élément e
sous la forme d'un Tuple
.
my_list.index
renvoie le premier index de e
. Si le premier index n'est pas i
, l'itération en cours e
n'est pas le premier e
de la liste.
Éditer
Je dois noter que ce n'est pas une bonne façon de le faire, en termes de performances. Ceci est juste une manière de le réaliser en utilisant uniquement une compression de liste.
En utilisant la propriété de base de Python Dictionary:
inp=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
d={i for i in inp}
print d
La sortie sera:
set([u'nowplaying', u'job', u'debate', u'PBS', u'thenandnow'])
def get_distinct(original_list):
distinct_list = []
for each in original_list:
if each not in distinct_list:
distinct_list.append(each)
return distinct_list
set
peut vous aider à filtrer les éléments en double de la liste. Cela fonctionnera bien pour les éléments str
, int
ou Tuple
, mais si votre liste contient des éléments dict
ou autres list
, vous obtiendrez alors TypeError
exceptions.
Voici une solution générale préservant les commandes pour gérer certains types (pas tous) non-hashable:
def unique_elements(iterable):
seen = set()
result = []
for element in iterable:
hashed = element
if isinstance(element, dict):
hashed = Tuple(sorted(element.iteritems()))
Elif isinstance(element, list):
hashed = Tuple(element)
if hashed not in seen:
result.append(element)
seen.add(hashed)
return result
Tout d’abord, l’exemple que vous avez donné n’est pas une liste valide.
example_list = [u'nowplaying',u'PBS', u'PBS', u'nowplaying', u'job', u'debate',u'thenandnow']
Supposons que si ci-dessus est la liste d'exemple. Vous pouvez ensuite utiliser la recette suivante comme exemple pour la documentation itertools qui peut renvoyer les valeurs uniques et préserver l’ordre tel que vous semblez le nécessiter. L'iterable ici est la liste_exemples
from itertools import ifilterfalse
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in ifilterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
En prime, Counter
est un moyen simple d'obtenir à la fois les valeurs uniques et le nombre pour chaque valeur:
from collections import Counter
l = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
c = Counter(l)
def setlist(lst=[]):
return list(set(lst))
Pour obtenir des valeurs uniques à partir de votre liste , utilisez le code ci-dessous:
trends = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
output = set(trends)
output = list(output)
IMPORTANT: L'approche ci-dessus ne fonctionnera pas si l'un des éléments de la liste n'est pas hashable , ce qui est le cas pour mutable types, par exemple liste ou dict .
trends = [{'super':u'nowplaying'}, u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
output = set(trends)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
Cela signifie que vous devez être sûr que la liste trends
ne contiendra toujours que des éléments pouvant être hachés, sinon vous devrez utiliser un code plus sophistiqué:
from copy import deepcopy
try:
trends = [{'super':u'nowplaying'}, [u'PBS',], [u'PBS',], u'nowplaying', u'job', u'debate', u'thenandnow', {'super':u'nowplaying'}]
output = set(trends)
output = list(output)
except TypeError:
trends_copy = deepcopy(trends)
while trends_copy:
trend = trends_copy.pop()
if trends_copy.count(trend) == 0:
output.append(trend)
print output
En plus des réponses précédentes, qui disent que vous pouvez convertir votre liste pour définir, vous pouvez le faire de cette façon aussi
mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenadnow']
mylist = [i for i in set(mylist)]
la sortie sera
[u'nowplaying', u'job', u'debate', u'PBS', u'thenadnow']
bien que l'ordre ne soit pas préservé.
Une autre réponse plus simple pourrait être (sans utiliser des ensembles)
>>> t = [v for i,v in enumerate(mylist) if mylist.index(v) == i]
[u'nowplaying', u'PBS', u'job', u'debate', u'thenadnow']
Je suis surpris de constater que personne n'a jusqu'ici donné une réponse directe préservant l'ordre:
def unique(sequence):
"""Generate unique items from sequence in the order of first occurrence."""
seen = set()
for value in sequence:
if value in seen:
continue
seen.add(value)
yield value
Il générera les valeurs afin qu'il fonctionne avec plus que de simples listes, par exemple. unique(range(10))
. Pour obtenir une liste, appelez simplement list(unique(sequence))
, comme ceci:
>>> list(unique([u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']))
[u'nowplaying', u'PBS', u'job', u'debate', u'thenandnow']
Il est nécessaire que chaque élément soit haschable et non seulement comparable, mais la plupart des éléments de Python le soient et il s’agit de O(n) et non de O (n ^ 2). fonctionne très bien avec une longue liste.
utiliser set pour dédupliquer une liste, retourner en tant que liste
def get_unique_list(lst):
if isinstance(lst,list):
return list(set(lst))
output=[]
trends=list(set(trends))
Vous pouvez utiliser des ensembles. Juste pour être clair, j'explique quelle est la différence entre une liste et un ensemble. Les ensembles sont une collection d'éléments non ordonnés. Les listes sont une collection d'éléments ordonnée. Alors,
unicode_list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job',u'debate', u'thenandnow']
list_unique=list(set(unicode_list))
print list_unique
[u'nowplaying', u'job', u'debate', u'PBS', u'thenandnow']
Mais: N'utilisez pas list/set pour nommer les variables. Cela provoquera l'erreur suivante: EX: au lieu d'utiliser liste au lieu de liste_unicode dans la liste ci-dessus.
list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job',u'debate', u'thenandnow']
list_unique=list(set(list))
print list_unique
list_unique=list(set(list))
TypeError: 'list' object is not callable
Set est une collection d'éléments ordonnés et uniques. Donc, vous pouvez utiliser set comme ci-dessous pour obtenir une liste unique:
unique_list = list(set([u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']))
Si vous souhaitez obtenir des éléments uniques d'une liste et conserver leur ordre d'origine, vous pouvez utiliser la structure de données OrderedDict
de la bibliothèque standard de Python:
from collections import OrderedDict
def keep_unique(elements):
return list(OrderedDict.fromkeys(elements).keys())
elements = [2, 1, 4, 2, 1, 1, 5, 3, 1, 1]
required_output = [2, 1, 4, 5, 3]
assert keep_unique(elements) == required_output
En fait, si vous utilisez Python ≥ 3.6, vous pouvez utiliser plain dict
pour cela:
def keep_unique(elements):
return list(dict.fromkeys(elements).keys())
C'est devenu possible après l'introduction de la représentation "compacte" de dict. Check it out ici . Bien que ceci "ait été considéré comme un détail de mise en œuvre et ne doit pas être invoqué".
Ma solution pour vérifier l’unicité du contenu tout en préservant la commande initiale:
def getUnique(self):
notunique = self.readLines()
unique = []
for line in notunique: # Loop over content
append = True # Will be set to false if line matches existing line
for existing in unique:
if line == existing: # Line exists ? do not append and go to the next line
append = False
break # Already know file is unique, break loop
if append: unique.append(line) # Line not found? add to list
return unique
Edit: Peut probablement être plus efficace en utilisant des clés de dictionnaire pour vérifier l'existence au lieu de faire une boucle de fichier complète pour chaque ligne, je n'utiliserais pas ma solution pour les grands ensembles.
Je sais que c'est une vieille question, mais voici ma solution unique: l'héritage de classe !:
class UniqueList(list):
def appendunique(self,item):
if item not in self:
self.append(item)
return True
return False
Ensuite, si vous souhaitez ajouter des éléments de manière unique à une liste, vous appelez simplement appendunique dans une UniqueList. Comme il hérite d’une liste, il agit essentiellement comme une liste. Vous pouvez donc utiliser des fonctions telles que index (), etc. Et comme il renvoie true ou false, vous pouvez savoir si l’ajout a réussi (élément unique) ou échoué (déjà dans les liste).
Pour obtenir une liste unique d'éléments dans une liste, utilisez une boucle for en ajoutant des éléments à une UniqueList (puis copiez-les dans la liste).
Exemple de code d'utilisation:
unique = UniqueList()
for each in [1,2,2,3,3,4]:
if unique.appendunique(each):
print 'Uniquely appended ' + str(each)
else:
print 'Already contains ' + str(each)
Impressions:
Uniquely appended 1
Uniquely appended 2
Already contains 2
Uniquely appended 3
Already contains 3
Uniquely appended 4
Copier pour lister:
unique = UniqueList()
for each in [1,2,2,3,3,4]:
unique.appendunique(each)
newlist = unique[:]
print newlist
Impressions:
[1, 2, 3, 4]