Récemment, j'ai remarqué que lorsque je convertis un list
en set
l'ordre des éléments est modifié et trié par caractère.
Considérons cet exemple:
x=[1,2,20,6,210]
print x
# [1, 2, 20, 6, 210] # the order is same as initial order
set(x)
# set([1, 2, 20, 210, 6]) # in the set(x) output order is sorted
Mes questions sont -
A set
est une structure de données non ordonnée.
N'utilisez pas un set
, mais plutôt collections.OrderedDict
:
>>> a = collections.OrderedDict.fromkeys([1, 2, 20, 6, 210])
>>> b = collections.OrderedDict.fromkeys([6, 20, 1])
>>> collections.OrderedDict.fromkeys(x for x in a if x not in b)
OrderedDict([(2, None), (210, None)])
Notez que l'ordre de b
n'a pas d'importance, donc ce peut être n'importe quelle valeur, mais ce devrait être une variable qui supporte les tests d'adhésion O(1)).
Edit : La réponse ci-dessus suppose que vous voulez pouvoir effectuer des opérations de réglage (ordonné) sur toutes les collections en cours, en particulier sur le résultat d'un ancien ensemble d'opération. Si cela n'est pas nécessaire, vous pouvez simplement utiliser des listes pour certaines des collections et des ensembles pour d'autres, par exemple.
>>> a = [1, 2, 20, 6, 210]
>>> b = set([6, 20, 1])
>>> [x for x in a if x not in b]
[2, 210]
Ceci perd la commande de b
, n'autorise pas les tests d'appartenance rapides sur a
et le résultat. Les ensembles permettent des tests rapides d’appartenance et les listes restent en ordre. Si vous avez besoin de ces deux fonctionnalités sur la même collection, utilisez collections.OrderedDict
.
Dans Python 3.6, il existe une autre solution pour Python 2 et 3:set()
maintenant devrait garder l'ordre, mais
>>> x = [1, 2, 20, 6, 210]
>>> sorted(set(x), key=x.index)
[1, 2, 20, 6, 210]
Répondant à votre première question, un ensemble est une structure de données optimisée pour les opérations sur les ensembles. Comme un ensemble mathématique, il n’impose ni ne maintient aucun ordre particulier des éléments. Le concept abstrait d'un ensemble n'impose pas l'ordre et la mise en œuvre n'est donc pas requise. Lorsque vous créez un ensemble à partir d'une liste, Python est libre de modifier l'ordre des éléments en fonction des besoins de l'implémentation interne qu'il utilise pour un ensemble, ce qui permet d'effectuer des opérations d'ensemble efficacement. .
Comme indiqué dans d'autres réponses, les ensembles sont des structures de données (et des concepts mathématiques) qui ne préservent pas l'ordre des éléments -
Cependant, en utilisant une combinaison d'ensembles et de dictionnaires, il est possible d'obtenir ce que vous voulez - essayez d'utiliser ces extraits:
# save the element order in a dict:
x_dict = dict(x,y for y, x in enumerate(my_list) )
x_set = set(my_list)
#perform desired set operations
...
#retrieve ordered list from the set:
new_list = [None] * len(new_set)
for element in new_set:
new_list[x_dict[element]] = element
Une implémentation du concept de score le plus élevé ci-dessus qui le ramène à une liste:
def SetOfListInOrder(incominglist):
from collections import OrderedDict
outtemp = OrderedDict()
for item in incominglist:
outtemp[item] = None
return(list(outtemp))
Testé (brièvement) sur Python 3.6 et Python 2.7.
En me basant sur la réponse de Sven, j'ai trouvé en utilisant des collections.
import collections
x=[1,2,20,6,210]
z=collections.OrderedDict.fromkeys(x)
z
OrderedDict([(1, None), (2, None), (20, None), (6, None), (210, None)])
Si vous souhaitez ajouter des éléments mais que vous le traitez toujours comme un ensemble, vous pouvez simplement faire:
z['nextitem']=None
Et vous pouvez effectuer une opération comme z.keys () sur le dict et obtenir l'ensemble:
z.keys()
[1, 2, 20, 6, 210]
Si vous avez un petit nombre d’éléments dans vos deux listes initiales sur lesquels vous voulez effectuer l’opération de définition de différence, au lieu d’utiliser collections.OrderedDict
qui complique la mise en oeuvre et la rend moins lisible, vous pouvez utiliser:
# initial lists on which you want to do set difference
>>> nums = [1,2,2,3,3,4,4,5]
>>> evens = [2,4,4,6]
>>> evens_set = set(evens)
>>> result = []
>>> for n in nums:
... if not n in evens_set and not n in result:
... result.append(n)
...
>>> result
[1, 3, 5]
Sa complexité temporelle n’est pas très bonne mais elle est nette et facile à lire.
C'est parce que l'ensemble est une structure de données non ordonnée.
Pour maintenir l'ordre, vous pouvez le faire comme suit:
x=[1,2,3,20,6,210,50,20];
print(sorted(set(x),key=x.index));
Comme vous le verrez de cette manière, vous pouvez effectuer des opérations définies sans perdre l’ordre initial.