OVH Cloud OVH Cloud

Dictionnaires, listes et bijections ...

8 réponses
Avatar
Thomas Paviot
Bonjour à tous,

Je souhaiterais construire un lien bijectif entre les éléments suivants:

1<->"bleu"
2<->"vert"
3<->"jaune"
4<->"rouge"
5<->"violet"

(cet exemple est un modèle de mon problème réel. Le problème est
indépendant du type d'objet).

Actuellement, j'utilise deux dictionnaires pour répondre à mon besoin :
chacun d'entre eux réalisant une surjection de l'ensemble des clés sur
l'ensemble des valeurs, j'arrive ainsi à réaliser ma bijection:

d1=[1:"bleu",2:"vert",3:"jaune",4:"rouge",5:"violet"]
d2=["bleu":1,"vert":2,"jaune":3,"rouge":4","violet":5]

Ensuite j'utilise au choix l'un ou l'autre de dictionnaires.

Je trouve cette méthode lourde et très inélégante. Connaîtriez-vous un
moyen plus simple et plus robuste pour arriver au résutat?

Thomas

8 réponses

Avatar
Gerard Flanagan
Thomas Paviot wrote:

Bonjour à tous,

Je souhaiterais construire un lien bijectif entre les éléments suivan ts:

1<->"bleu"
2<->"vert"
3<->"jaune"
4<->"rouge"
5<->"violet"

(cet exemple est un modèle de mon problème réel. Le problème est
indépendant du type d'objet).

Actuellement, j'utilise deux dictionnaires pour répondre à mon besoin :
chacun d'entre eux réalisant une surjection de l'ensemble des clés sur
l'ensemble des valeurs, j'arrive ainsi à réaliser ma bijection:

d1=[1:"bleu",2:"vert",3:"jaune",4:"rouge",5:"violet"]
d2=["bleu":1,"vert":2,"jaune":3,"rouge":4","violet":5]

Ensuite j'utilise au choix l'un ou l'autre de dictionnaires.

Je trouve cette méthode lourde et très inélégante. Connaîtriez- vous un
moyen plus simple et plus robuste pour arriver au résutat?


pour moi, 'bijectif' suggere '2-tuple':

INDEX = 0
ELEMENT = 1

d1=[ (1, "bleu"), (2, "vert"), (3, "jaune"), (4, "rouge"), (5,
"violet")]

print d1[3][ELEMENT]

for elem in d1:
print elem[INDEX], ' <-> ', elem[ELEMENT]


#----------------------------------------------------------------
print

d2= {'a': ('a', "bleu"), 'b': ('b', "vert"), 'c': ('c', "jaune"), 'd':
('d', "rouge"), 'e': ('e', "violet") }

print d2['e'][ELEMENT]

for key, value in d2.itervalues():
print key, ' <-> ', value

#----------------------------------------------------------------

Gerard

Avatar
Laurent Pointal
Bonjour à tous,

Je souhaiterais construire un lien bijectif entre les éléments suivants:

1<->"bleu"
2<->"vert"
3<->"jaune"
4<->"rouge"
5<->"violet"

(cet exemple est un modèle de mon problème réel. Le problème est
indépendant du type d'objet).

Actuellement, j'utilise deux dictionnaires pour répondre à mon besoin :
chacun d'entre eux réalisant une surjection de l'ensemble des clés sur
l'ensemble des valeurs, j'arrive ainsi à réaliser ma bijection:

d1=[1:"bleu",2:"vert",3:"jaune",4:"rouge",5:"violet"]
d2=["bleu":1,"vert":2,"jaune":3,"rouge":4","violet":5]

Ensuite j'utilise au choix l'un ou l'autre de dictionnaires.


S'il n'y a pas recouvrement entre tes deux ensembles... tu peux tout
mettre dans un dictionnaire... mais je ne trouve pas que ça soit
spécialement plus propre...

Je trouve cette méthode lourde et très inélégante. Connaîtriez-vous un
moyen plus simple et plus robuste pour arriver au résutat?


Tu peux faire un classe qui masque les deux dictionnaires, et des
méthodes pour mettre en place les bijections et pour récupérer les
correspondances. Il y aura le même chose derrière, une couche
d'indirection en plus, mais la lecture du code final sera plus simple -
et mis dans un joli module, ça sera réutilisable ailleurs...

A+

Laurent.

Avatar
bruno at modulix
Thomas Paviot wrote:
Bonjour à tous,

Je souhaiterais construire un lien bijectif entre les éléments suivants:

1<->"bleu"
2<->"vert"
3<->"jaune"
4<->"rouge"
5<->"violet"

(cet exemple est un modèle de mon problème réel. Le problème est
indépendant du type d'objet).

Actuellement, j'utilise deux dictionnaires pour répondre à mon besoin :
chacun d'entre eux réalisant une surjection de l'ensemble des clés sur
l'ensemble des valeurs, j'arrive ainsi à réaliser ma bijection:

d1=[1:"bleu",2:"vert",3:"jaune",4:"rouge",5:"violet"]
d2=["bleu":1,"vert":2,"jaune":3,"rouge":4","violet":5]


<typo>
remplacer les [] par des {}, bien sûr
</typo>

Ensuite j'utilise au choix l'un ou l'autre de dictionnaires.

Je trouve cette méthode lourde et très inélégante. Connaîtriez-vous un
moyen plus simple et plus robuste pour arriver au résutat?


Dans le principe, ça reste la méthode générique la plus efficace. Quant
à la la laideur, il suffit d'encapsuler le tout dans une classe qui gère
l'index inverse. Une première solution possible est:

class Biject(object):
def __init__(self, data):
self._map = data
self._rmap = dict((v, k) for k, v in data.items())

def __getitem__(self, key):
try:
return self._map[key]
except KeyError:
return self._rmap[key]

def __setitem__(self, key, val):
if self._rmap.has_key(key):
self._map[key] = key
self._rmap[val] = val
else:
self._map[key] = val
self._rmap[val] = key

Le problème est que cette solution donne une certaine précédence à l'un
des deux mappings (celui passé en argument).

Si, comme dans ton cas, tu a clairement deux types distincts pour les
clées et les valeurs, tu peux simplifier (enfin... façon de parler) les
choses:

import types

class Biject2(object):
""" assume data is either
* a dict with int keys and string values
* a sequence of (int, str) tuples
* a sequence of strings
the 'base' optional arg is used in the last case
as the base for indexing.
"""
def __init__(self, data, base=0):
if type(data) is types.DictType:
self._map = data
elif type(data[0]) is types.TupleType and len(data[0]) == 2:
self._map = dict(data)
else:
self._map = dict((k + base, v) for k, v in enumerate(data))
self._rmap = dict((v, k) for k, v in self._map.items())

def __getitem__(self, index):
if type(index) in types.StringTypes:
return self._rmap[index]
else:
return self._map[index]

def __setitem__(self, index, value):
if type(index) in types.StringTypes:
index, value = value, index
self._map[index] = value
self._rmap[value] = index

def __len__(self):
return len(self._map)


Il y a certainement d'autres solutions (et certainement de meilleures
solutions), mais le principe reste le même: créer un type qui masque les
détails d'implémentation, histoire de ne plus s'en soucier dans le code
client.

HTH
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"

Avatar
Gerard Flanagan
bruno at modulix wrote:

Thomas Paviot wrote:
Bonjour à tous,

Je souhaiterais construire un lien bijectif entre les éléments suiv ants:

1<->"bleu"
2<->"vert"
3<->"jaune"
4<->"rouge"
5<->"violet"

(cet exemple est un modèle de mon problème réel. Le problème est
indépendant du type d'objet).

Actuellement, j'utilise deux dictionnaires pour répondre à mon beso in :
chacun d'entre eux réalisant une surjection de l'ensemble des clés sur
l'ensemble des valeurs, j'arrive ainsi à réaliser ma bijection:

d1=[1:"bleu",2:"vert",3:"jaune",4:"rouge",5:"violet"]
d2=["bleu":1,"vert":2,"jaune":3,"rouge":4","violet":5]


<typo>
remplacer les [] par des {}, bien sûr
</typo>

Ensuite j'utilise au choix l'un ou l'autre de dictionnaires.

Je trouve cette méthode lourde et très inélégante. Connaîtrie z-vous un
moyen plus simple et plus robuste pour arriver au résutat?


Dans le principe, ça reste la méthode générique la plus efficace. Quant
à la la laideur, il suffit d'encapsuler le tout dans une classe qui g ère
l'index inverse. Une première solution possible est:

class Biject(object):
def __init__(self, data):
self._map = data
self._rmap = dict((v, k) for k, v in data.items())

def __getitem__(self, key):
try:
return self._map[key]
except KeyError:
return self._rmap[key]

def __setitem__(self, key, val):
if self._rmap.has_key(key):
self._map[key] = key
self._rmap[val] = val
else:
self._map[key] = val
self._rmap[val] = key



ou peut-etre:

class Biject(object):
def __init__(self, data):
self._map = {}
for k, v in data.iteritems():
self[k] = v

def __getitem__(self, key):
return self._map[key]

def __setitem__(self, key, val):
self._map[key] = val
self._map[val] = key

def __delitem__(self, key):
val = self._map[key]
del self._map[key]
del self._map[val]

d1={1:"bleu",2:"vert",3:"jaune",4:"rouge",5:"violet"}
biject = Biject(d1)
print biject['bleu']
1




Gerard



Avatar
Laurent Pointal
ou peut-etre:

class Biject(object):
def __init__(self, data):
self._map = {}
for k, v in data.iteritems():
self[k] = v

def __getitem__(self, key):
return self._map[key]

def __setitem__(self, key, val):
self._map[key] = val
self._map[val] = key

def __delitem__(self, key):
val = self._map[key]
del self._map[key]
del self._map[val]

d1={1:"bleu",2:"vert",3:"jaune",4:"rouge",5:"violet"}
biject = Biject(d1)
print biject['bleu']
1




Gerard



A condition que les deux ensembles soient exclusifs. Sinon, il faut
prendre 2 maps et distinguer ensemble A / ensemble B.




Avatar
Eric Deveaud
Thomas Paviot wrote:
Bonjour à tous,

Je souhaiterais construire un lien bijectif entre les éléments suivants:

1<->"bleu"
2<->"vert"
3<->"jaune"
4<->"rouge"
5<->"violet"


je ne suis pas sur de comprendre le problème, à partir d'un dictionnaire vous
souhaitez pouvoir sortir la valeur associé a une clef (comportement normal)
MAIS aussi pouvoir récupérer la clef associée à une valeur donnée ??

je vois un petit problème.
vos valeurs sont elles uniques, n'avez vous aucun risque de collision de
valeurs ??

si oui en se basant sur un dictionaire, comme vous le suggérez, on pourrai
proposer ceci

def biject(d, key):
try:
return d[key]
except KeyError:
for k,v in d.iteritems():
if v == key:
return k
raise KeyError, key

pour faire plus propre, j'envisagerai de créer une classe particulière
permattant de gérer ce genre de choses.

Eric

--
Que demande le peuple ?
Un livre sur les gnous, avec des images [] à découper, et ce serait auto-

collant, et le manchot, il mettrait le papier de linuxminimum autour du, et,
-+- Gregg in Guide du linuxien pervers - "Non, pas les gens en blanc !"

Avatar
Méta-MCI
Bonjour !

La solution des deux dictionnaires est suffisante, si les contenus
n'évoluent pas.

Dans le cas inverse, ça devient nettement plus complexe. En effet, la
modification d'une valeur devra se faire à deux endroits.

Et, pour gérer ça sans copies, en gérant l'intégrité des données, je vois,
soit pondre une classe, soit créer une structure de données complexe,
composée d'une liste des listes des valeurs, et de deux dictionnaires, dont
toutes les données pointent sur (contiennent) un élément de la liste.
On pourrait aussi mettre ça dans une classe.

@-salutations

Michel Claveau
Avatar
Gerard Flanagan
Laurent Pointal wrote:

ou peut-etre:

class Biject(object):
def __init__(self, data):
self._map = {}
for k, v in data.iteritems():
self[k] = v

def __getitem__(self, key):
return self._map[key]

def __setitem__(self, key, val):
self._map[key] = val
self._map[val] = key

def __delitem__(self, key):
val = self._map[key]
del self._map[key]
del self._map[val]

d1={1:"bleu",2:"vert",3:"jaune",4:"rouge",5:"violet"}
biject = Biject(d1)
print biject['bleu']
1




Gerard



A condition que les deux ensembles soient exclusifs. Sinon, il faut
prendre 2 maps et distinguer ensemble A / ensemble B.


Oui, un dict comme

d2={1:4, 2:1, 3:5, 4:2, 5:3}

est ambigue au point de vue de '__getitem__' . On peut peut-etre soit
preciser ce qu'on veut - l'ensemble 'de depart' ou 'd'arrivee' - soit
lister des valeurs multiples ( s'il y en a).

donc, soit:

-------------------------------------------------------
class Biject2(object):
def __init__(self, data):
self._map = {}
for k, v in data.iteritems():
self[k] = v

def __getitem__(self, (key, idx)):
return self._map[(key,idx)]

def __setitem__(self, key, val):
self._map[(key, 0)] = val
self._map[(val, 1)] = key

d2={1:4, 2:1, 3:5, 4:2, 5:3}
biject = Biject2(d2)

assert biject[1,0] == 4
assert biject[1,1] == 2

-------------------------------------------------------

soit:
------------------------------------------------------

class Biject3(object):
def __init__(self, data):
self._map = {}
for k, v in data.iteritems():
self[k] = v

def __getitem__(self, key):
ret1 = None
ret2 = None
if self._map.has_key( (key,0) ):
ret1 = self._map[(key,0)]
if self._map.has_key( (key,1) ):
ret2 = self._map[(key,1)]
if (ret1 and ret2) and (ret1 != ret2):
return [ret1, ret2]
else:
return ret1 or ret2

def __setitem__(self, key, val):
self._map[(key, 0)] = val
self._map[(val, 1)] = key

d2={1:4, 2:1, 3:5, 4:2, 5:3}
biject = Biject3(d2)

assert biject[1] == [4, 2]
assert biject[5] == 3