Forum: Italian Ruby user group Hash con due elementi come chiave

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
738ac200073d9cca7cbd98ce98894865?d=identicon&s=25 Njna Njna (njna)
on 2008-12-05 14:36
ciao a tutti, ho il seguente hash

@strade = Hash([])

nel quale associo ad una coppia di citta i kilometri

esempio @strade[["milano","roma"]] = [650, 800]
vuolre dire che ci sono due strade da milano a roma, una di 600 km e una
di 800 km.

in un controllo ho notato che il sistema non fa distinzione tra
@strade[["milano","roma"]] e @strade[["roma","milano"]] e ho bisogno che
siano due cose distinte, anche perchè ci possono essere ulteriori strade
e ulteriori kilometri.. come posso fare?


grazie a tutti
8768bcdbda1adf80e4da6744268868af?d=identicon&s=25 Pietro Giorgianni (giorgian)
on 2008-12-05 14:57
(Received via mailing list)
2008/12/5 Njna Njna <v_orecchia@hotmail.com>:
> in un controllo ho notato che il sistema non fa distinzione tra
> @strade[["milano","roma"]] e @strade[["roma","milano"]] e ho bisogno che
> siano due cose distinte, anche perchè ci possono essere ulteriori strade
> e ulteriori kilometri.. come posso fare?

ciao, non è quello che hai chiesto, ma perché non usare una hash tipo
{"Roma" => {"Milano", ...}, ...}?
i dati in che forma li hai?

riguardo alla domanda, non mi viene in mente una soluzione usando
Array; che ne dici di costruire la chiave, ad esempio "Roma | Milano"?
738ac200073d9cca7cbd98ce98894865?d=identicon&s=25 Njna Njna (njna)
on 2008-12-05 14:59
ciao Pietro, come faccio a costruire la chiave "Roma | Milano"? ho
proprio esigenza di associare ad una coppia di dati più valori che
sarebbero i chilometri


Pietro Giorgianni wrote:
> 2008/12/5 Njna Njna <v_orecchia@hotmail.com>:
>> in un controllo ho notato che il sistema non fa distinzione tra
>> @strade[["milano","roma"]] e @strade[["roma","milano"]] e ho bisogno che
>> siano due cose distinte, anche perch� ci possono essere ulteriori strade
>> e ulteriori kilometri.. come posso fare?
>
> ciao, non � quello che hai chiesto, ma perch� non usare una hash tipo
> {"Roma" => {"Milano", ...}, ...}?
> i dati in che forma li hai?
>
> riguardo alla domanda, non mi viene in mente una soluzione usando
> Array; che ne dici di costruire la chiave, ad esempio "Roma | Milano"?
4f4122bc3b9999d9050f0b1a10b63251?d=identicon&s=25 Andrea Reginato (reis)
on 2008-12-05 15:24
(Received via mailing list)
2008/12/5 Njna Njna <v_orecchia@hotmail.com>

> ciao Pietro, come faccio a costruire la chiave "Roma | Milano"? ho
> proprio esigenza di associare ad una coppia di dati più valori che
> sarebbero i chilometri
>
>
Non so se sia quello che serve a te, ma riprendendo quanto detto da njna
ti
faccio un semplice esempio utilizzando le Hash.

irb(main):001:0> strade = {}   #=> {}
irb(main):002:0> strade['milano'] = {'roma' => [650, 800]}   #=>
{"roma"=>[650, 800]}
irb(main):003:0> strade   #=> {"milano"=>{"roma"=>[650, 800]}}
irb(main):004:0> strade['roma'] = {'milano' => [800, 650]}   #=>
{"milano"=>[800, 650]}
irb(main):005:0> strade['milano']['roma']   #=> [650, 800]
irb(main):006:0> strade['roma']['milano']  #=> [800, 650]

Come vedi dalle due ultime righe se metti in ordine differente le
città che
ti interessano avrai dei risultati differenti.

--
Andrea Reginato, http://mikamai.com
Writing http://sensejs.wordpress.com/
Collaborating http://therubymine.it
Reading http://stacktrace.it
738ac200073d9cca7cbd98ce98894865?d=identicon&s=25 Njna Njna (njna)
on 2008-12-05 15:28
quindi dichiaro il mio hash così:

@strade = Hash.new{}

poi quando aggiungo la prima coppia supponiamo milano - roma km 600
faccio @strade[milano] = ????? e poi?



Andrea Reginato wrote:
> 2008/12/5 Njna Njna <v_orecchia@hotmail.com>
>
>> ciao Pietro, come faccio a costruire la chiave "Roma | Milano"? ho
>> proprio esigenza di associare ad una coppia di dati pi� valori che
>> sarebbero i chilometri
>>
>>
> Non so se sia quello che serve a te, ma riprendendo quanto detto da njna
> ti
> faccio un semplice esempio utilizzando le Hash.
>
> irb(main):001:0> strade = {}   #=> {}
> irb(main):002:0> strade['milano'] = {'roma' => [650, 800]}   #=>
> {"roma"=>[650, 800]}
> irb(main):003:0> strade   #=> {"milano"=>{"roma"=>[650, 800]}}
> irb(main):004:0> strade['roma'] = {'milano' => [800, 650]}   #=>
> {"milano"=>[800, 650]}
> irb(main):005:0> strade['milano']['roma']   #=> [650, 800]
> irb(main):006:0> strade['roma']['milano']  #=> [800, 650]
>
> Come vedi dalle due ultime righe se metti in ordine differente le
> citt� che
> ti interessano avrai dei risultati differenti.
>
> --
> Andrea Reginato, http://mikamai.com
> Writing http://sensejs.wordpress.com/
> Collaborating http://therubymine.it
> Reading http://stacktrace.it
8768bcdbda1adf80e4da6744268868af?d=identicon&s=25 Pietro Giorgianni (giorgian)
on 2008-12-05 15:47
(Received via mailing list)
Il 5 dicembre 2008 15.28, Njna Njna <v_orecchia@hotmail.com> ha scritto:
> quindi dichiaro il mio hash così:
>
> @strade = Hash.new{}

anche @strade = {} va bene

> poi quando aggiungo la prima coppia supponiamo milano - roma km 600
> faccio @strade[milano] = ????? e poi?

@strade = {}

def get_route(partenza, destinazione)
  @strade[partenza] && @strade[partenza][destinazione]
end

def set_route(partenza, destinazione, altro)
  @strade[partenza] ||= {}
  @strade[partenza][destinazione] = altro
end
24035e6fafa4c747fa9c8f2e9b39c6fd?d=identicon&s=25 Andrea Campi (Guest)
on 2008-12-05 15:57
(Received via mailing list)
On Fri, 5 Dec 2008 14:59:36 +0100, Njna Njna wrote:
> ciao Pietro, come faccio a costruire la chiave "Roma | Milano"? ho
> proprio esigenza di associare ad una coppia di dati più valori che
> sarebbero i chilometri

Perchè non creare invece un oggetto Itinerario, con due attributi
(@partenza e @arrivo, ad esempio)?
A quel punto useresti un'istanza di quell'oggetto come chiave e saresti
libero di definire le condizioni di identità di due oggetti.
E soprattutto avresti codice molto più pulito e object oriented.

Andrea
738ac200073d9cca7cbd98ce98894865?d=identicon&s=25 Njna Njna (njna)
on 2008-12-05 16:00
può aver senso questo? faccio inserimento controllano se c'era già qlc
valore o meno

def aggiungi_strada(c1,c2,t)
     if (@strade[c1][c2]!=nil)
           @strade[c1][c2] << t
      else
           @strade[c1]= {}
           @strade[c1][c2] = t
      end
end


Pietro Giorgianni wrote:
> Il 5 dicembre 2008 15.28, Njna Njna <v_orecchia@hotmail.com> ha scritto:
>> quindi dichiaro il mio hash cos�:
>
>> @strade = Hash.new{}
>
> anche @strade = {} va bene
>
>> poi quando aggiungo la prima coppia supponiamo milano - roma km 600
>> faccio @strade[milano] = ????? e poi?
>
> @strade = {}
>
> def get_route(partenza, destinazione)
>   @strade[partenza] && @strade[partenza][destinazione]
> end
>
> def set_route(partenza, destinazione, altro)
>   @strade[partenza] ||= {}
>   @strade[partenza][destinazione] = altro
> end
738ac200073d9cca7cbd98ce98894865?d=identicon&s=25 Njna Njna (njna)
on 2008-12-05 16:03
andrea riesci a farmi un esempio di come faresti tu? così mi schiarisco
le idee che ho un sacco di confusione
grazie mille


Andrea Campi wrote:
> On Fri, 5 Dec 2008 14:59:36 +0100, Njna Njna wrote:
>> ciao Pietro, come faccio a costruire la chiave "Roma | Milano"? ho
>> proprio esigenza di associare ad una coppia di dati pi� valori che
>> sarebbero i chilometri
>
> Perch� non creare invece un oggetto Itinerario, con due attributi
> (@partenza e @arrivo, ad esempio)?
> A quel punto useresti un'istanza di quell'oggetto come chiave e saresti
> libero di definire le condizioni di identit� di due oggetti.
> E soprattutto avresti codice molto pi� pulito e object oriented.
>
> Andrea
Eaf76558277bad82dcf2405a36208eca?d=identicon&s=25 Pierpaolo Sanna (Guest)
on 2008-12-05 16:12
(Received via mailing list)
Ciao,
secondo me il problema sta nel modo in cui inizializzi l'hash
@strade = Hash([])
così assegni lo stesso array per tuttu le chiavi dell'hash.Per assegnare
un
array diverso per ogni chiave devi fare così
@strade = Hash.new {|h,k| h[k] = []}

ciao
2008/12/5 Njna Njna <v_orecchia@hotmail.com>
738ac200073d9cca7cbd98ce98894865?d=identicon&s=25 Njna Njna (njna)
on 2008-12-05 16:19
Perfetto, funziona!!!!! grazie a tutti!!!
solo più una domanda... perchè non sempre è necessario definire l'hash
in quel modo?

uso spesso l'hash ma non mi era mai capitata l'esigenza di una
inizializzazione del genere.. come mai?

ancora grazie!!


Pierpaolo Sanna wrote:
> Ciao,
> secondo me il problema sta nel modo in cui inizializzi l'hash
> @strade = Hash([])
> cos� assegni lo stesso array per tuttu le chiavi dell'hash.Per assegnare
> un
> array diverso per ogni chiave devi fare cos�
@strade = Hash.new {|h,k| h[k] = []}
>
> ciao
> 2008/12/5 Njna Njna <v_orecchia@hotmail.com>
4f4122bc3b9999d9050f0b1a10b63251?d=identicon&s=25 Andrea Reginato (reis)
on 2008-12-05 16:44
(Received via mailing list)
2008/12/5 Njna Njna <v_orecchia@hotmail.com>

> Perfetto, funziona!!!!! grazie a tutti!!!
> solo più una domanda... perchè non sempre è necessario definire l'hash
> in quel modo?
>
> uso spesso l'hash ma non mi era mai capitata l'esigenza di una
> inizializzazione del genere.. come mai?
>

Allora, per definire una Hash base i comandi che si possono usare sono
due
(una vale l'altra)

  strade = Hash.new
  strade = {}

A dirla tutta Hash([]) non l'ho mai visto utilizzare, e almeno a mio
parere
non è molto chiaro.
Comunque l'importante è che abbia rislto il prob ;-)

--
Andrea Reginato, http://mikamai.com
Writing http://sensejs.wordpress.com/
Collaborating http://therubymine.it
Reading http://stacktrace.it
738ac200073d9cca7cbd98ce98894865?d=identicon&s=25 Njna Njna (njna)
on 2008-12-05 17:05
ok ma quando basta mettere Hash{} e quando invece è necessario
specificare tra parentesi una cosa del genere? {|h,k| h[k] = []}
4f4122bc3b9999d9050f0b1a10b63251?d=identicon&s=25 Andrea Reginato (reis)
on 2008-12-05 17:45
(Received via mailing list)
On Fri, Dec 5, 2008 at 5:05 PM, Njna Njna <v_orecchia@hotmail.com>
wrote:

> ok ma quando basta mettere Hash{} e quando invece è necessario
> specificare tra parentesi una cosa del genere? {|h,k| h[k] = []}
>

Credo si stia fecendo un pochino di confusione.
Guardando la documentazione ufficiale sulla classe
Hash<http://www.ruby-doc.org/core/classes/Hash.html>se specifichi una
cosa del genere significa che per ogni chiave non
specificata avrai un array vuoto, cioè []. Ecco un esempio

irb(main):012:0> strade = Hash.new([])
=> {}
irb(main):013:0> strade['milano'] = {'roma' => 650}
=> {"roma"=>650}
irb(main):014:0> strade['milano']
=> {"roma"=>650}
irb(main):015:0> strade['bologna']
=> []

Come vedi, per la chiave Bologna non è ancora stata definita una chiave,
quindi mi ritorna il default che è stato definito come array vuoto, cioè [].
La seconda notazione che chiedi è un pochino più potente, ma in questo caso
non cambia nulla.

irb(main):016:0> strade = Hash.new{|h, k| h[k] = []}
=> {}
irb(main):017:0> strade['milano'] = {'roma' => 650}
=> {"roma"=>650}
irb(main):018:0> strade['milano']
=> {"roma"=>650}
irb(main):019:0> strade['bologna']
=> []

Se sei curioso troverai altro nella doc ufficiale per qualche caso più
complesso ;-)


--
Andrea Reginato, http://mikamai.com
Writing http://sensejs.wordpress.com/
Collaborating http://therubymine.it
Reading http://stacktrace.it
24035e6fafa4c747fa9c8f2e9b39c6fd?d=identicon&s=25 Andrea Campi (Guest)
on 2008-12-05 17:53
(Received via mailing list)
On Fri, 5 Dec 2008 16:03:14 +0100, Njna Njna wrote:
> andrea riesci a farmi un esempio di come faresti tu? così mi schiarisco
> le idee che ho un sacco di confusione
> grazie mille

class Itinerario
  def initialize(args = {})
    @a = args
  end

  def from
    @a[:from]
  end

  def to
    @a[:to]
  end

  def eql?(other)
    return self.from == other.from && self.to == other.to
  end

  def hash
    return (self.from.hash << 16) | self.to.hash
  end
end


Facendo così puoi scrivere:

strade = {}
strade[Itinerario.new(:from => 'Milano', :to => 'Roma')] = 650

# o anche

s = {
  Itinerario.new(:from => 'Milano', :to => 'Roma') = 650 # sovrascrive
quello precedente
  Itinerario.new({:from => 'Milano', :to => 'Brescia'}) => 50,
  Itinerario.new({:from => 'Roma', :to => 'Milano'}) => 700
 }
strade.merge!(s)

puts strade.inspect


La cosa più comoda è che se un domani vuoi supportare anche il caso di
Milano -> Roma via Ancona, cambi solo la classe Itinerario e hai fatto.

Ciao,
  Andrea
24035e6fafa4c747fa9c8f2e9b39c6fd?d=identicon&s=25 Andrea Campi (Guest)
on 2008-12-05 18:00
(Received via mailing list)
On Fri, 5 Dec 2008 16:00:57 +0100, Njna Njna wrote:
> può aver senso questo? faccio inserimento controllano se c'era già qlc
> valore o meno
>
> def aggiungi_strada(c1,c2,t)
>      if (@strade[c1][c2]!=nil)

Al limite, @strade[c1].has_key?(c2)

>            @strade[c1][c2] << t
>       else
>            @strade[c1]= {}
>            @strade[c1][c2] = t
>       end
> end

A meno che t sia un array, non può funzionare, visto che nel primo caso
appendi e nel secondo assegni.

Onestamente trovo questo approccio eccessivamente procedurale. Con
rispetto parlando, Ruby non è PHP.

Ciao,
  Andrea
Eaf76558277bad82dcf2405a36208eca?d=identicon&s=25 Pierpaolo Sanna (Guest)
on 2008-12-05 21:31
(Received via mailing list)
Prima ho espresso un pò male il concetto. Con

Hash.new(obj)

viene ustao lo stesso oggetto (obj) per tutti i valori di default.
Invece
con

Hash.new {|h,k| ....}

ogni volta che richiedi il valore di una chiave non ancora presente
nell'hash viene chiamato il blocco, che dovrebbe restituire il valore di
default, ma in questo caso è un oggetto differente di volta in volta.
io utilizzo questa forma

h = Hash.new {|h,k| h[k] = []}

perchè così non devo preoccuparmi di fare i controlli sulla chiave prima di
appendere un elemento nell'array , cioè posso semplicamente fare così

h["nouva chiave"]  << "elemento da appendere"

in questo modo se la chiave è già presente, il nuovo elemento viene accodato
all'array, se la chiave non è presente viene creato un nuovo array e poi
inserito l'elemento
altrimenti dovrei fare così

if h.has_key?("nouva chiave")
  h << "elemento da appendere"
else
 h["nuova chiave] = []
 h["nuova chiave] << "elemento da appendere"
end






2008/12/5 Njna Njna <v_orecchia@hotmail.com>
C01072ccffb1f2d23f8b5f686e5b106a?d=identicon&s=25 gabriele renzi (Guest)
on 2008-12-05 22:28
(Received via mailing list)
> con
>
> Hash.new {|h,k| ....}
>
> ogni volta che richiedi il valore di una chiave non ancora presente
> nell'hash viene chiamato il blocco, che dovrebbe restituire il valore di
> default, ma in questo caso è un oggetto differente di volta in volta.

Aggiungo: probabilmente non ti sei mai scontrato con il problema
perché usavi come valore predefinito un oggetto immutabile, ad esempio un
numero.

Per cui facendo
hsh = Hash.new(0)
hsh[:foo] +=1
puts hsh[:foo], hsh[:bar] #=> 1 0

In questo caso non stavi modificando l'oggetto "0" ma lo stavi
sostituendo con l'oggetto "1", mentre nel caso degli array il
cambiamento avveniva nell'oggetto immagazzinato come valore.
0c79c9f33bb2aebfc175a7596f6ca099?d=identicon&s=25 Tucano (Guest)
on 2008-12-07 15:11
(Received via mailing list)
Magari complico solo la situazione, ma perche non usi un grafo per
rappresentare le strade tra le citta'?

Nello specifico dovrebbe essere un grafo direzionato con le citta'
come nodi (vertici) e le distanze in kilometri sono attributi degli
edges

Ho trovato questa libreria in Ruby:
http://rgl.rubyforge.org/rgl/index.html

tipo:

 >> require 'rgl/adjacency'
 >> dg=RGL::DirectedAdjacencyGraph["Milano","Roma","Roma","Milano"]
=> #<RGL::DirectedAdjacencyGraph:0x5aa500
@vertice_dict={"Roma"=>#<Set: {"Milano"}>, "Milano"=>#<Set:
{"Roma"}>}, @edgelist_class=Set>
 >> dg.vertices
=> ["Roma", "Milano"]
 >> dg.edges
=> [#<RGL::Edge::DirectedEdge:0x5a5a78 @target="Milano",
@source="Roma">, #<RGL::Edge::DirectedEdge:0x5a5910 @target="Roma",
@source="Milano">]


Siccome il grafo e' direzionato abbiamo entrambi gli edges (quindi
distingue tra roma-->milano e milano-->roma).

A questo punto non ti rimane che attaccare agli edges un attributo (la
distanza in kilometri)

La cosa interessante e' che, essendo un grafo, ci puoi applicare una
serie di interessanti metodi di ricerca, sorting, shortest paths, etc...

ciao

Il giorno 05/dic/08, alle ore 14:36, Njna Njna ha scritto:
This topic is locked and can not be replied to.