Obtenir les valeurs uniques d'une liste en python [dupliquer]
cette question a déjà une réponse ici:
- suppression des doublons dans les listes 41 réponses
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']
This un code qui fonctionne:
output = []
for x in trends:
if x not in output:
output.append(x)
print output
est-il une meilleure solution que je devrais utiliser?
30 réponses
déclarez D'abord votre liste correctement, séparées par des virgules. 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'utiliser comme une liste, vous devez le convertir en retour à la liste en faisant:
mynewlist = list(myset)
une Autre possibilité, probablement plus rapide serait d'utiliser un set depuis le début, au lieu d'une liste. Alors votre code devrait être:
output = set()
for x in trends:
output.add(x)
print output
comme il a été souligné, les ensembles ne pas maintenir l'ordre original. Si vous en avez besoin, vous devriez consulter le ensemble commandé .
Pour être cohérent avec le type que j'utiliserais:
mylist = list(set(mylist))
l'exemple que vous avez fourni ne correspond pas aux listes en Python. Ça ressemble à un dicton imbriqué, ce qui n'est probablement pas ce que vous vouliez.
une liste de Python:
a = ['a', 'b', 'c', 'd', 'b']
pour obtenir des articles uniques, il suffit de le transformer en un ensemble (que vous pouvez transformer à nouveau dans une liste si nécessaire):
b = set(a)
print b
>>> set(['a', 'b', 'c', 'd'])
si nous avons besoin de maintenir l'ordre des éléments, que pensez-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 une autre 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 - 1er octobre 2016
une autre solution avec reduce
, mais cette fois sans .append
ce qui le rend plus lisible 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: ayez à l'esprit que plus nous lisons, plus le script est non-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.8063139915466309
timeit.timeit('reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])', setup=setup)
2.216820001602173
timeit.timeit('reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])', setup=setup)
2.948796033859253
timeit.timeit('reduce(lambda l, x: l if x in l else l+[x], mylist, [])', setup=setup)
2.9785239696502686
ANSWERING COMMENTS
parce que @monica a posé une bonne question sur "comment cela fonctionne-t-il?". Pour tous ceux qui ont des problèmes à le découvrir. Je vais essayer de donner une explication plus profonde sur la façon dont cela fonctionne et ce qui sorcellerie se passe ici ;)
donc 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 pas les résultats désirés à l'intérieur de la variable unique
, mais seulement à l'intérieur de la variable used
. C'est parce que pendant la compréhension de la liste .append
modifie le used
variable et retourne None
.
donc, pour obtenir les résultats dans la variable unique
, et toujours utiliser la même logique avec .append(x) if x not in used
, nous devons déplacer ce .append
appel sur le côté droit de la liste de compréhension et juste retourner x
sur le côté gauche.
Mais si nous sommes trop naïfs et juste aller avec:
>>> unique = [x for x in mylist if x not in used and used.append(x)]
>>> print unique
[]
nous n'obtiendrons rien en retour.
à nouveau, c'est parce que la .append
méthode retourne None
, et cela donne sur notre expression logique le regard suivant:
x not in used and None
Ce ne sera toujours:
- valeur
False
quandx
est dansused
, - évalue à
None
quandx
n'est pas dansused
.
et dans les deux cas ( False
/ None
), cette valeur sera traitée comme falsy
et nous obtiendrons une liste vide.
mais pourquoi cela évalue à None
quand x
n'est pas dans used
? Quelqu'un peut demander.
Eh bien c'est parce que c'est ainsi que court-circuit opérateurs fonctionne de Python .
l'expression
x and y
évalue d'abord x; si x est fausse, sa valeur est retour; sinon, y est évalué et la valeur résultante est retourner.
quand x
n'est pas utilisée (c'est à dire lorsque son True
) la prochaine partie ou l'expression sera évaluée ( used.append(x)
) et sa valeur ( None
) sera retourné.
Mais c'est ce que nous voulons pour obtenir le éléments uniques d'une liste avec des doublons, nous voulons les .append
dans une nouvelle liste que lorsque nous ils sont venus à travers pour une première fois.
donc nous voulons vraiment évaluer used.append(x)
seulement quand x
n'est pas dans used
, peut-être que s'il y a un moyen de transformer cette valeur None
en une valeur truthy
nous serons très bien, non?
Eh bien, oui et voici où le deuxième type d'opérateurs de short-circuit
viennent jouer.
L'expression
x or y
évalue d'abord x; si x est vrai, sa valeur est retour; sinon, y est évalué et la valeur résultante est retourner.
nous savons que .append(x)
sera toujours falsy
, donc si nous ajoutons juste un or
à côté de lui, nous aurons toujours la partie suivante. C'est pourquoi nous écrivons:
x not in used and (used.append(x) or True)
donc nous pouvons évaluer used.append(x)
et obtenir True
comme un résultat, seulement quand la première partie de l'expression (x not in used)
est True
.
on peut voir la même chose 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:
- ajouter
x
àl
et retourner quel
quandx
n'est pas dansl
. Merci à laor
déclaration.append
est évalué etl
est retourné après cela. - Retour
l
intact lorsquex
est dansl
quel type est votre variable de sortie?
Python jeux sont ce que 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 de sortie.ajouter(elem) et assurez-vous qu'ils sont uniques.
Avertissement: des ensembles de NE PAS conserver l'original de l'ordre de la liste.
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 la solution la plus simple-
list=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
list=set(list)
set-collection sans ordre d'éléments uniques. Liste des éléments peuvent être transmises à l'ensemble du constructeur. Ainsi, passer la liste avec des éléments dupliqués, nous obtenons mis avec des éléments uniques et le transformer de nouveau à la liste puis obtenir la liste avec des éléments uniques. Je ne peux rien dire sur la performance et la mémoire, mais j'espère que ce n'est pas si important avec de petites listes.
list(set(my_not_unique_list))
simple et court.
même ordre liste unique utilisant seulement 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
comme un tuple
.
my_list.index
renvoie le premier indice de e
. Si le premier index n'est pas i
, alors le e
de l'itération courante n'est pas le premier e
de la liste.
Modifier
je dois noter que ce n'est pas une bonne façon de le faire, du point de vue de la performance. C'est juste une façon qui l'atteint en utilisant seulement une compression de liste.
si vous utilisez numpy dans votre code (ce qui pourrait être un bon choix pour de plus grandes quantités de données), consultez 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 voir, numpy supporte non seulement les données numériques, les tableaux de chaînes de caractères sont également possibles. Bien sûr, le résultat est un numpy tableau, mais il n'a pas d'importance beaucoup, parce qu'il est encore se comporte comme une séquence:
>>> for word in np.unique(wordsList):
... print word
...
PBS
debate
job
nowplaying
thenandnow
si vous voulez vraiment avoir une liste de Python à la vanille, vous pouvez toujours appeler list().
cependant, le résultat est automatiquement trié, comme vous pouvez le voir à partir des fragments de code ci-dessus. Vérifier numpy unique sans tri si l'ordre de liste de conservation est nécessaire.
obtenir des éléments uniques de la liste
mylist = [1,2,3,4,5,6,6,7,7,8,8,9,9,10]
utilisant la logique Simple de Sets-Sets sont une liste unique d'articles
mylist=list(set(mylist))
In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
À L'Aide De Simple Logique
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]
utilisant la méthode pop ->pop supprime le dernier ou l'é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]
Utilisation De Numpy
import numpy as np
np.unique(mylist)
In [0]: mylist
Out[0]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
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']
supposez Si ci-dessus est la liste d'exemple. Ensuite, vous pouvez utiliser la recette suivante comme donner l'exemple d'itertools doc qui peut retourner les valeurs uniques et préserver l'ordre comme vous semblez avoir besoin. L'itérable ici est l'example_list
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 utilisant la propriété de base du dictionnaire Python:
inp=[u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
d={i for i in inp}
print d
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
en bonus, 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)
en plus des réponses précédentes, qui disent que vous pouvez convertir votre liste en set, 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)]
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 les sets)
>>> t = [v for i,v in enumerate(mylist) if mylist.index(v) == i]
[u'nowplaying', u'PBS', u'job', u'debate', u'thenadnow']
pour obtenir des valeurs uniques de votre code d'utilisation de la liste 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 d'une liste n'est pas hachable 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 trends
liste ne contient toujours que des éléments hachurables sinon vous devez 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
je suis surpris que personne jusqu'à présent n'ait donné une réponse directe de maintien de 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 de sorte qu'il fonctionne avec plus que de simples listes, par exemple unique(range(10))
. Pour obtenir une liste, il suffit d'appeler 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 a l'exigence que chaque élément est hachable et pas seulement comparable, mais la plupart des choses en Python est et il est O(N) et non O(N^2), donc fonctionnera très bien avec une longue liste.
- au début de votre code, déclarez que votre liste de sortie est vide:
output=[]
- au lieu de votre code vous pouvez utiliser ce code
trends=list(set(trends))
Vous pouvez utiliser des ensembles. Juste pour être clair, je vais expliquer quelle est la différence entre une liste et un ensemble. les décors sont une collection sans ordre d'éléments uniques.Les listes sont ordonnées collection d'éléments. So,
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. Il sera la cause de l'erreur: EX: Au lieu d'utiliser la liste au lieu de unicode_list dans la précédente.
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
peut vous aider à filtrer les éléments de la liste sont des doublons. Cela fonctionnera bien pour les éléments str
, int
ou tuple
, mais si votre liste contient dict
ou d'autres list
, alors vous finirez avec des exceptions TypeError
.
Voici une solution générale de conservation des commandes pour traiter certains (pas tous) types non-hachables:
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
ensemble est une collection d'éléments ordonnés et uniques. Ainsi, vous pouvez utiliser défini 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']))
ma solution pour vérifier le contenu pour l'unicité mais préserver l'ordre original:
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: Probablement peut être plus efficace en utilisant des clés de dictionnaire pour vérifier l'existence au lieu de faire une boucle de dossier entière pour chaque ligne, Je ne voudrais pas utiliser ma solution pour les grands ensembles.
from collections import OrderedDict
seq = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
# Unordered (hashable items)
list(set(seq))
# Out: ['thenandnow', 'PBS', 'debate', 'job', 'nowplaying']
# Order-preserving
list(OrderedDict.fromkeys(seq))
# Out: ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']
alternativement en Python 3.6+:
# Order-preserving
list(dict.fromkeys(seq))
# Out: ['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']
utiliser set pour supprimer une liste, retourner comme liste
def get_unique_list(lst):
if isinstance(lst,list):
return list(set(lst))
Pour les longs tableaux
s = np.empty(len(var))
s[:] = np.nan
for x in set(var):
x_positions = np.where(var==x)
s[x_positions[0][0]]=x
sorted_var=s[~np.isnan(s)]
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 voulez ajouter uniquement des éléments à une liste, vous appelez simplement annexe sur une liste unique. Parce qu'il hérite d'une liste, il agit essentiellement comme une liste, donc vous pouvez utiliser des fonctions comme index() etc. Et parce qu'il retourne true ou false, vous pouvez savoir si Ajouter réussi (unique item) ou échoué (déjà dans la liste).
à obtenez une liste unique d'éléments d'une liste, utilisez une boucle pour ajouter des éléments à une liste unique (puis copiez sur la liste).
exemple de code d'usage:
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)
Imprime:
Uniquely appended 1
Uniquely appended 2
Already contains 2
Uniquely appended 3
Already contains 3
Uniquely appended 4
Copie de la liste:
unique = UniqueList()
for each in [1,2,2,3,3,4]:
unique.appendunique(each)
newlist = unique[:]
print newlist
Imprime:
[1, 2, 3, 4]
si vous voulez obtenir des éléments uniques d'une liste et garder leur ordre original, alors vous pouvez employer OrderedDict
structure de données 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 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 " des dicts. Regardez ici . Bien que cela "ait considéré un détail de mise en œuvre et ne devrait pas être comptée".
essayez cette fonction, c'est similaire à votre code mais c'est une plage dynamique.
def unique(a):
k=0
while k < len(a):
if a[k] in a[k+1:]:
a.pop(k)
else:
k=k+1
return a