Forum: Italian Ruby user group Hash e valore di default

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.
Njna N. (Guest)
on 2008-11-24 13:17
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?
Claudio F. (Guest)
on 2008-11-24 13:32
(Received via mailing list)
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
Njna N. (Guest)
on 2008-11-24 13:41
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())
Claudio F. (Guest)
on 2008-11-24 13:55
(Received via mailing list)
ok,
guarda in prenota_socio invece di usare << prova =
dovrebbe funzionarti
Njna N. (Guest)
on 2008-11-24 14:02
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
Claudio F. (Guest)
on 2008-11-24 14:08
(Received via mailing list)
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
Njna N. (Guest)
on 2008-11-24 14:09
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
> [].
Claudio F. (Guest)
on 2008-11-24 14:25
(Received via mailing list)
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(p)
end

in questo modo controlla se esiste l'array 's', nel caso lo crea,
e accora sempre i parametri di 'p'
Njna N. (Guest)
on 2008-11-24 15:26
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(p)
> end
>
> in questo modo controlla se esiste l'array 's', nel caso lo crea,
> e accora sempre i parametri di 'p'
Njna N. (Guest)
on 2008-11-24 15:34
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?
Claudio F. (Guest)
on 2008-11-24 15:35
(Received via mailing list)
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
Njna N. (Guest)
on 2008-11-24 16:29
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
Claudio F. (Guest)
on 2008-11-24 16:33
(Received via mailing list)
mi dovresti postare la classe che hai creato, piu' i parametri che passi
altrimenti mi risulta difficile aiutarti.
Njna N. (Guest)
on 2008-11-24 16:46
Attachment: njna.rb (0 Bytes)
per comodità di commenti ti allego questo file
Pierpaolo S. (Guest)
on 2008-11-24 16:59
(Received via mailing list)
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>
Claudio F. (Guest)
on 2008-11-24 17:13
(Received via mailing list)
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
Njna N. (Guest)
on 2008-11-24 17:21
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
Claudio F. (Guest)
on 2008-11-24 17:30
(Received via mailing list)
tu il confronto lo fai tra due valori che sono stringhe
oppure due date?
Njna N. (Guest)
on 2008-11-24 17:33
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?
Claudio F. (Guest)
on 2008-11-24 17:40
(Received via mailing list)
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.
Njna N. (Guest)
on 2008-11-24 17:46
devo usare per forza quella classe. mi è imposta. per aggiungere il
metodo < cosa intendi?


Claudio F. wrote:
> 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.
Claudio F. (Guest)
on 2008-11-24 17:51
(Received via mailing list)
Se guardi alla classe che mi hai inviato, puoi trovare
il metodo

def <=>(d)
...

dovresti fare, sempre se non sia gia' presente,

def <(d)
...

con la logica che la data che tu passi al metodo <, non convertita con
to_s, sia superiore a quella che la invoca.
This topic is locked and can not be replied to.