Hash e valore di default


#1

Ciao a tutti

ho una classe Agenzia che viene inizializzata comne segue:

def initialize(listasoci)
@soci = listasoci
@guadagni = Hash.new(0)
@impegni = Hash.new([])
end

dove si prende come input un array di stringhe che rappresentano i nomi
dei soci dell’agenzia. Il metodo inizializza una lista di stringhe
@soci contenente i nomi dei soci, un hash @guadagni che memorizza il
guadagno totale di ogni socio e un hash @impegni che memorizza la lista
delle offerte che sono state assegnate a ogni socio.

Nella classe ho un metodo prenota_socio(p,s) che assegna un impegno p ad
un socio s quindi avrò una cosa del genere:

@impegni[s] << p

il mio problema è che non solo al socio s ma ad ogni socio di @soci
viene aggiunto l’impegno p.

Mi è stato detto che quando definisco l’hash @impegni = Hash.new([])
quello che succede e’ che la STESSA lista vuota diventa il valore di
default per TUTTE le chiavi dell’hash. Dato che poi si aggiungono
elementi alla lista con << (che modifica la lista senza crearne
un’altra) per tutta l’esecuzione del programma a tutte le chiavi
dell’hash corrisponde esattamente la stessa lista.

qualcuno mi sa dire come ovviare alla cosa?


#2

Ciao,
credo tu possa risolvere la cosa usando attr_accessor

praticamente viene cosi’

class Agenzia
attr_accessor :soci, :guadagni, :impegni

def initialize
@soci = {}
@guadagni = {}
@impegni = {}
end

invochi la class

a = Agenzia.new
a.soci[“nomesocio”] = “qualcosa”
a.soci[“nomesocio”] = 100
a.soci[“nomesocio”] = {“impegni” => 100}

spero che hai capito il modo, in pratica attr_accessor ti crea delle
funzioni al volo per scrivere o leggere dentro delle variabili della
classe


#3

Ciao Claudio,
guarda io uso già attr_accessor. in agenzia prima di initialize ho

attr_accessor :soci, :guadagni, :impegni

poi ho “prenota_socio” che fa questa @impegni[s] << p e invece di
aggiungere p solo agli impegni di s li aggiunge a tuttii soci.
dalla nota che mi è stata fatta si dice che praticamente faccio
riferimento sempre alla stessa lista quindi è per quello che mi risulta
che tutti i soci hanno quell’impegno…

devo mica fare una cosa del genere, sempre se possibile, che ogni volta
crea una lista nuova?

@impegni = Hash.new(Array.new())


#4

con

@impegni[s] = p

non funziona comunque… mette sempre a tutti i soci l’impegno p…

non sono una guru di ruby ma da quello che ho capito il problema è
proprio in @impegni = Hash.new([]) che fa sempre riferimento allo stesso
[].

Claudio F. wrote:

ok,
guarda in prenota_socio invece di usare << prova =
dovrebbe funzionarti


#5

ok,
guarda in prenota_socio invece di usare << prova =
dovrebbe funzionarti


#6

ecco la prova che ho fatto ed a me non scrive in ogni record

class Agenzie
attr_accessor :impegni
def initialize
@impegni = Hash.new([])
end

def prenota_socio(p,s)
@impegni[s] = p
end
end

k = Agenzie.new
k.prenota_socio(“100”, “nome1”)
k.prenota_socio(“200”, “nome2”)
p k.impegni
#a me restituisce questo
{“nome1” => “100”, “nome2” => “200”}

k.prenota_socio(“300”, “nome1”)
p k.impegni

e sempre in risultato e’

{“nome1” => “300”, “nome2” => “200”}

sia che scrivo Hash.new([]) o Hash.new()

prova questo e vedi se succede come succede a me


#7

allora prenota_socio deve essere in questo modo

considero p un array e s una stringa

def prenota_socio(p,s)
@impegni[s] = [] if @impegni.has_key?(s) == false
@impegni[s].concat§
end

in questo modo controlla se esiste l’array ‘s’, nel caso lo crea,
e accora sempre i parametri di ‘p’


#8

più che altro quello di cui ho bisogno è che impegni abbia associata al
socio s una lista che inizialmente è vuota e che viene riempita man
mano… per quello avevo messo <<. mettendo un = non è che tutte le
volte mi risulta sempre e solo un impegno, in particolare l’ultimo
inserito, sovrascrive ogni volta quello vecchio??

Njna N. wrote:

con

@impegni[s] = p

non funziona comunque… mette sempre a tutti i soci l’impegno p…

non sono una guru di ruby ma da quello che ho capito il problema è
proprio in @impegni = Hash.new([]) che fa sempre riferimento allo stesso
[].


#9

ti ringrazio ma non funziona nemmeno così… la concat da dei problemi

Claudio F. wrote:

allora prenota_socio deve essere in questo modo

considero p un array e s una stringa

def prenota_socio(p,s)
@impegni[s] = [] if @impegni.has_key?(s) == false
@impegni[s].concat§
end

in questo modo controlla se esiste l’array ‘s’, nel caso lo crea,
e accora sempre i parametri di ‘p’


#10

le false speranze…

mettendo così:

if !@impegni.has_key?(s)
@impegni[s] = []
@impegni[s] << p
@guadagni[s] += p.paga
rit = true
else
[…]

il risultato è corretto… secondo te può andare?


#11

Claudio eprnso che il problema ora stia in un parte dentro quel metodo
dove uso l’operatore astronave… mi sa che lo uso sbagliato… tu mi sai
spiegare come funziona?

Claudio F. wrote:

allora il problema deve essere nei parametri che passi alla funzione
poiche’ lo script funziona sul mio computer.

mi scrivi un caso reale dei parametri che passi?
usa il comando p nello script per farti stampare a schermo i valori

claudio


#12

mi dovresti postare la classe che hai creato, piu’ i parametri che passi
altrimenti mi risulta difficile aiutarti.


#13

allora il problema deve essere nei parametri che passi alla funzione
poiche’ lo script funziona sul mio computer.

mi scrivi un caso reale dei parametri che passi?
usa il comando p nello script per farti stampare a schermo i valori

claudio


#14

Modifica così il metodo initialize

def initialize(listasoci)
@soci = listasoci
@guadagni = Hash.new(0)
@impegni = Hash.new {|h,k| h[k] = []}
end

2008/11/24 Njna N. removed_email_address@domain.invalid


#15

per comodità di commenti ti allego questo file


#16

Il concat prima non ti funzionava per il semplice motivo che tu non
passavi un array, ma una stringa oppure un oggetto, quindi ecco
come rivedrei la tua funzione prenota_socio ed ho fatto una versione
di intereseca

def prenota_socio(p,s)
tmp = 0
rit = false

    raise(SocioSconosciuto, s) unless @soci.include?(s)

    if @impegni.include?(s)
            for i in @impegni[s]
                    tmp += 1 if i.interseca(p)
            end

            if tmp == 0
                    @impegni[s].push(p)
                    @guadagni[s] += p.paga
                    rit = true
            else
                    rit = false
            end
    else
            @impegni[s] = []
            @impegni[s].push(p)
            @guadagni[s] += p.paga
            rit = true
    end

    return rit

end

def interseca(o)

se i.inizio ed i.fine sono inferiori a o.inizio ritorno true

    if self.inizio < o.inizio && self.fine < o.inizio
            return true
    else
            return false
    end

end


#17

ti ringrazio, la funzione interseca però nn mi pare funzioni…

Claudio F. wrote:

Il concat prima non ti funzionava per il semplice motivo che tu non
passavi un array, ma una stringa oppure un oggetto, quindi ecco
come rivedrei la tua funzione prenota_socio ed ho fatto una versione
di intereseca

def interseca(o)

se i.inizio ed i.fine sono inferiori a o.inizio ritorno true

    if self.inizio < o.inizio && self.fine < o.inizio
            return true
    else
            return false
    end

end


#18

tu il confronto lo fai tra due valori che sono stringhe
oppure due date?


#19

sono due oggetti appartenenti a questa classe.

class Dt
include Comparable

attr_reader :g, :m, :a

def initialize(gi,me,an)
if an<1970 || me<1 || me>12 || gi<1 || gi > 31
raise DataIllegale, “#{gi}/#{me}/#{an}”
elsif me==2 && gi>29
raise DataIllegale, “#{gi}/#{me}/#{an}” # febbraio ha al massimo
29gg
elsif me==2 && (an%4!=0) && gi>28
raise DataIllegale, “#{gi}/#{me}/#{an}” # se non e’ bisestile al
max 28gg
elsif [11,4,6,9].include?(me) && gi>30
raise DataIllegale, “#{gi}/#{me}/#{an}” # 30g ha nov con apr, giu,
e set
end
@g=gi;@m = me; @a = an
end

def <=>(d) # operatore astronave per il confronto fra date
if(@a!=d.a)
return @a-d.a
elsif(@m!=d.m)
return @m-d.m
else
return @g-d.g
end
end

def to_s
“#@g/#@m/#@a
end

end

se mi dai una mail ti mando il file completo vero e proprio. qui nn mi
pare il caso postarlo.

Claudio F. wrote:

tu il confronto lo fai tra due valori che sono stringhe
oppure due date?


#20

non serve che mi mandi il file, perche’ ricreare una classe Date che
gia’ esiste in ruby. Il fatto che la funzione che ti ho fatto io
interseca non funziona e’ dovuta da questa classe quindi hai due
possibilita’:

  • usare Date di ruby(che ti permette di fare i confronti)
  • aggiungere alla tua classe il metodo <

a te la scelta.