Forum: Italian Ruby user group problema semplice ruby

4095f049a398cb42c1ca334ab3e620bf?d=identicon&s=25 Dario Di Zio (davek3)
on 2014-02-05 12:08
Ciao a tutti sto seguendo una guida per imparare a programmare in ruby
un esercizio richiede la creazione di un "software" che calcoli gli anni
bisestili tra un range di anni e che li PUTSi. allora seguendo lo
sviluppo di un altro utente ho tirato fuori questo.

# encoding: utf-8
Puts 'Calcolatore di anni bisestili'
puts 'Inserisci una data di partenza'
partenza=gets.chomp
x=partenza.to_i
puts 'inserisci una data di fine'
fine=gets.chomp
y=fine.to_i
while x<=y
  if x%4==0 and x%100!=0
  puts x.to_s+' è un anno bisestile'
  end
  x=x+1
end
puts 'Non ci sono altri anni bisestili in questa serie'


l'esercizio riporta le istruzioni per il calcolo di un bisestile,
ovvero:
Un anno è bisestile se il suo numero è divisibile per 4, con l’eccezione
che gli anni secolari (quelli divisibili per 100) sono bisestili solo se
divisibili per 400

sono riuscito a fare in modo che se il resto riportato dall'anno diviso
per 4 è 0 lo riporti.
se il resto riportato dall'anno diviso 100 sia diverso da 0 riporti
anche quello.
ora dovrei aggiungere la funzione che dica che se però è divisibile per
400 allora riporti anche quelli.

grazie
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2014-02-05 15:28
(Received via mailing list)
Ciao Dario,

2014-02-05 Dario Di Zio <dave-the-best@hotmail.it>:

> ora dovrei aggiungere la funzione che dica che se però è divisibile per
> 400 allora riporti anche quelli.
>

sai come capire se un numero è divisibile per 400?
5ce16d85034e08079db3cafeb5b8ff09?d=identicon&s=25 Davide Rambaldi (Guest)
on 2014-02-05 15:35
(Received via mailing list)
io lo so! io lo so!

posso rispondere?
5ce16d85034e08079db3cafeb5b8ff09?d=identicon&s=25 Davide Rambaldi (Guest)
on 2014-02-05 15:38
(Received via mailing list)
che poi la definizione giusta e’:

"Un anno è bisestile se è divisibile per 400 oppure è divisibile per 4
ma non per 100.”

credo
Cb8e3a1650513848561ca38f84399fa1?d=identicon&s=25 Fabrizio Regini (freegenie)
on 2014-02-05 15:50
(Received via mailing list)
puoi barare e vedere se l'ultimo giorno di febbraio per ogni anno è il
29.


2014-02-05 Davide Rambaldi <davide.rambaldi@gmail.com>:
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2014-02-05 15:50
(Received via mailing list)
Rambaldi, lei no che è in punizione.

[image: Inline images 1]

2014-02-05 Davide Rambaldi <davide.rambaldi@gmail.com>:
Dfa0e5f195b6f312006b465809b76b0b?d=identicon&s=25 Emanuele DelBono (Guest)
on 2014-02-05 16:10
(Received via mailing list)
Perch non

require 'date'
Date.leap?(2014) #=> false

?


2014-02-05 Dario Di Zio <dave-the-best@hotmail.it>:
4095f049a398cb42c1ca334ab3e620bf?d=identicon&s=25 Dario Di Zio (davek3)
on 2014-02-05 16:22
ho risolto, solo non capisco perchè prima non funzionava, mettendo ad
esempio
if x%4==0 and x%100!=0 and x%400==0
invece mettendo il 100 il 400 in parentesi con OR funziona. mi potreste
spiegare il perchè grazie


# encoding: utf-8
puts 'Inserisci una data di partenza'
partenza=gets.chomp
x=partenza.to_i
puts 'inserisci una data di fine'
fine=gets.chomp
y=fine.to_i
while x<=y
  if x%4==0 and (x%100!=0 or x%400==0)
  puts x.to_s+' è un anno bisestile'
  end
  x=x+1
end
puts 'Non ci sono altri anni bisestili in questa serie'


PS: non conosco molte funzioni che avete riportato. siccome sto seguendo
una guida e insegna le cose passo passo. mi devo arrangiare con quel che
so fino ad ora.
5ce16d85034e08079db3cafeb5b8ff09?d=identicon&s=25 Davide Rambaldi (Guest)
on 2014-02-05 18:37
(Received via mailing list)
Puoi tranquillamente fare a meno delluso delloperatore %

Considerato che ruby di default tronca le divisioni se sono due interi:

es:

> 7 / 2
=> 3

Puoi usare questa feature per calcolare il resto:

anni = (ARGV[0] .. ARGV[1])
anni.to_a.each { |a|
  leap = lambda do
    if ( (a.to_i / 400 * 400) == a.to_i)
      return true
    end
    if ( (a.to_i / 100 * 100) == a.to_i)
      return false
    end
    if ( (a.to_i / 4 * 4) == a.to_i)
      return true
    end
    return false
  end
  puts leap.call
}


Notare che con questa fai bella figura con il prof in quanto:

1. mostri con arroganza la tua conoscenza dello strong typing in Ruby
2. ti pavoneggi con lambda
3. fai finta di usare la programmazione funzionale

Ma io ho fatto questa versione MIGLIORE e VELOCE che funziona nel 75%
dei casi (accettabile)

anni = (ARGV[0] .. ARGV[1])
anni.to_a.each { |a|
  leap = lambda do
    return false
  end
  puts leap.call
}

Ciao

Davide
5ce16d85034e08079db3cafeb5b8ff09?d=identicon&s=25 Davide Rambaldi (Guest)
on 2014-02-05 18:46
(Received via mailing list)
On 05 Feb 2014, at 16:22, Dario Di Zio <dave-the-best@hotmail.it> wrote:

> ho risolto, solo non capisco perch prima non funzionava, mettendo ad
> esempio
> if x%4==0 and x%100!=0 and x%400==0
> invece mettendo il 100 il 400 in parentesi con OR funziona. mi potreste
> spiegare il perch grazie

Considera la definizione:

"Un anno  bisestile se  divisibile per 400 oppure  divisibile per 4 ma
non per 100.

Quindi lordine dei tuoi conditional e importante

quindi:

1. verifico se e divisibile per 400 (se si e bisestile e punto)
2. verifico che non sia divisibile per 100 (se e divisibile per 100 non
e bisestile)
3. verifico che sia divisibile per 4 (se e divisibile per 4 ma non per
100, condizione 2) e bisestile
4. nessuno dei precedenti? non e bisestile


Ciao e buon divertimento

PS: non dare ascolto a quelli che ti dicono di usare Date.leap? che i
rubyisti sono come i gioiellieri: hanno sempre una gemma da rivenderti
:-)


Davide R
4095f049a398cb42c1ca334ab3e620bf?d=identicon&s=25 Dario Di Zio (davek3)
on 2014-02-05 18:50
grazie a tutti, dopo il lavoro mi ci rimetto e ci do un occhiata.
ps: lo faccio per passione e sto seguendo una guida. quindi nessuno
vedrà il mio operato :D (sto però valutando l'uni di informatica)

le funzioni che uso sono quelle che conosco fino ad ora quindi ad
esempio il post di 'davide rambaldi' non l'ho capito, non perchè non è
stato chiaro o per altro, ma perchè non conosco ancora quelle funzioni.

grazie
5ce16d85034e08079db3cafeb5b8ff09?d=identicon&s=25 Davide Rambaldi (Guest)
on 2014-02-05 19:15
(Received via mailing list)
> le funzioni che uso sono quelle che conosco fino ad ora quindi ad
> esempio il post di 'davide rambaldi' non l'ho capito, non perch non
> stato chiaro o per altro, ma perch non conosco ancora quelle funzioni.

ops mi scuso,

provo  a mettere dei commenti

# USAGE: ruby script.rb <ANNO-INIZIO> <ANNO-FINE>
# Es:
# ruby script.rb 1998 2000

#  qui prendo i primi due argomenti passati da linea di comando
# ( ARGV e un array degli argomenti passati da linea di comando )
# e li converto in un RANGE (cosi mi mette in automatico gli elementi
mancanti
anni = ( ARGV[0] .. ARGV[1] )


# 1. Converti il tuo Range in un array con la funzione to_a (to array)
ora il mio input e' [1998,1999,2000]
# 2. Iterazione nellarray di date con il metodo "each"
anni.to_a.each { |a|

     # qui definisco una funzione anonima, senza nome con lambda
        # e la metto nelloggetto leap
  # il metodo to_i converte una stringa (gli argomenti da linea di
comando sono stringhe) in un numero (to Integer)
  leap = lambda do
    if ( (a.to_i / 400 * 400) == a.to_i)
      return true
    end
    if ( (a.to_i / 100 * 100) == a.to_i)
      return false
    end
    if ( (a.to_i / 4 * 4) == a.to_i)
      return true
    end
    return false
  end

  # qui chiamo la funzione anonima definita prima e stampo il risultato
  puts leap.call
}


un saluto e buon lavoro!

DR
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2014-02-05 19:17
(Received via mailing list)
2014-02-05 Dario Di Zio <dave-the-best@hotmail.it>:

> ho risolto, solo non capisco perchè prima non funzionava, mettendo ad
> esempio
> if x%4==0 and x%100!=0 and x%400==0
> invece mettendo il 100 il 400 in parentesi con OR funziona. mi potreste
> spiegare il perchè grazie
>

la definizione corretta di anno bisestile che ha menzionato Davide è:

x % 400 == 0 or (x % 100 != 0 and x % 4 == 0)

A or (B and C)

quella che stai usando te ora è:

x % 4 == 0 and (x % 100 != 0 or x % 400 == 0)

C and (B or A)

ora, queste due espressioni non sono identiche, infatti se costruissi la
tabella di verità, ti renderesti conto che:

A, B, C => A or (B and C), C and (B or A)
true, false, false => true, false
true, true, false => true, false

Tradotto: ci sono due casi in cui le due condizioni, a parità di input,
non
danno lo stesso output.

L'aspetto curioso è che nonostante a livello di composizione logica le
due
espressioni non siano identiche, considerando le implicazioni
matematiche,
non esistono dei numeri tali che il loro valore generi le due condizioni
in
cui l'output delle espressioni differirebbe.

Tradotto: non mi sembra esistano numeri tali per cui

A == true, B == false, C == false
A == true, B == true,  C == false

(almeno nell'intervallo che ho provato io: (1..10_000_000))

Due consigli:

1) usa gli operatori && e || al posto di "and" e "or" quando devi
valutare
espressioni booleane (
http://devblog.avdi.org/2010/08/02/using-and-and-or-in-ruby/)
2) usa gli spazi tra gli operatori "x <= y" al posto di "x<=y"

Have fun :-)

# encoding: utf-8
1a45b192d0bbaf167afb43a41859e313?d=identicon&s=25 Ju Liu (Guest)
on 2014-02-05 19:24
(Received via mailing list)
Ciao,

se ti può interessare eccoti una soluzione che ritengo abbastanza
"ruby-ista":

>
> class Integer
>   def multiple_of?(number)
>     self % number == 0
>   end
> end
>

Innanzitutto, le classi in Ruby sono "open", nel senso che possiamo
aprirle
in qualsiasi momento e aggiungere dei nostri metodi negli oggetti. In
questo caso, sto aggiungendo un metodo "multiple_of?" in tutti gli
Integer
che ci dirà se il numero che analizziamo è multiplo o no.


> class LeapYear
>   def self.in_range(range)
>     range.to_a.select do |n|
>       n.multiple_of?(400) || (
>         n.multiple_of?(4) && !n.multiple_of?(100)
>       )
>     end
>   end
> end
>

Questa classe prende in input un oggetto che in Ruby si chiama range e
descrive un intervallo di valori: per esempio scrivere (1..6).to_a è
uguale
a [1,2,3,4,5,6]. A quel punto cicla tra tutti i numeri presenti
all'interno
del range e seleziona quelli che:

   - sono multipli di 400, oppure
   - sono multipli di 4 ma non di 100

Se vedi usiamo il metodo "multiple_of?" che abbiamo appena aggiunto
prima.

Ti incollo anche il test automatico scritto con rspec che valida il
comportamento della classe, forse è un argomento ancora un po' avanzato,
però secondo me ti fai comunque un'idea su come funziona :)


>
> end
>


    Ju

--
M.Sc. Ju Liu
Twitter: @arkh4m <http://twitter.com/arkh4m>
Skype: johnny_arkham
Card: http://zerp.ly/ju-liu
--
Società Cooperativa weLaika
Corso Vigevano 14/B, 10154 Torino (TO), Italy
http://welaika.com - info@welaika.com


2014-02-05 maurizio de magnis <maurizio.demagnis@gmail.com>:
5ce16d85034e08079db3cafeb5b8ff09?d=identicon&s=25 Davide Rambaldi (Guest)
on 2014-02-05 19:26
(Received via mailing list)
On 05 Feb 2014, at 19:23, Ju Liu <ju.liu@welaika.com> wrote:

> se ti pu interessare eccoti una soluzione che ritengo abbastanza
> "ruby-ista":

woa woa woa

anche con il test!

io voto la soluzione di Ju Liu!
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2014-02-05 19:27
(Received via mailing list)
ora però vogliamo la gemma ;-)


2014-02-05 Davide Rambaldi <davide.rambaldi@gmail.com>:
4095f049a398cb42c1ca334ab3e620bf?d=identicon&s=25 Dario Di Zio (davek3)
on 2014-02-05 21:04
OH, grazie mille a tutti, mi avete aperto un mondo davanti, purtroppo
come ho già detto il metodo che ho utilizzato è il massimo che ho potuto
fare perchè seguo un percorso/guida, ma grazie mille sia per le
delucidazioni che per le soluzioni alternative, sicuramente le capirò
meglio tra poco che passerò alle classi e altro. grazie ancora e a
presto

end :)
321db48bf4bdf48da05e781325aed20a?d=identicon&s=25 Maurizio De magnis (olistik)
on 2014-02-05 21:17
(Received via mailing list)
Ciao Ju :-)

mmh, posso fare un raise ExcessiveTrickiness.new? ;-)

IMHO, se vogliamo andare di apertura delle classi:

class Fixnum
>   def is_leap_year?
>     self % 400 == 0 || (self % 4 == 0 && self % 100 != 0)
>   end
> end

(2000..2040).select(&:is_leap_year?)
> # ==> [2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036, 2040]


O con un approccio meno invasivo:

is_leap_year = ->(year) do
>   year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)
> end
> (2000..2040).select(&is_leap_year)
> # ==> [2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036, 2040]




2014-02-05 Ju Liu <ju.liu@welaika.com>:
1a45b192d0bbaf167afb43a41859e313?d=identicon&s=25 Ju Liu (Guest)
on 2014-02-05 21:32
(Received via mailing list)
Ciao Maurizio!

A discolpa del mio monkey-patching, activesupport l'ha fatto prima di
me:
http://apidock.com/rails/Integer/multiple_of%3F

Direi che delle due strade che proponi, l'approccio a lambda mi piace di
più, perché secondo me non è proprio responsabilità della classe Fixnum
di
riconoscere dei numeri che rappresentano anni bisestili.

Tra l'altro, all'inizio avevo provato con qualcosa come:

n.multiple_of?(400) or ( n.multiple_of?(4) and n.not_multiple_of?(100) )
>

perché mi fa ancora ridere che si possa far parlare Ruby con il
linguaggio
degli esseri umani ;)

    Ju

--
M.Sc. Ju Liu
Twitter: @arkh4m <http://twitter.com/arkh4m>
Skype: johnny_arkham
Card: http://zerp.ly/ju-liu
--
Società Cooperativa weLaika
Corso Vigevano 14/B, 10154 Torino (TO), Italy
http://welaika.com - info@welaika.com


2014-02-05 maurizio de magnis <maurizio.demagnis@gmail.com>:
4095f049a398cb42c1ca334ab3e620bf?d=identicon&s=25 Dario Di Zio (davek3)
on 2014-02-05 21:35
eccomi di nuovo qua, dopo neanche pochi minuti di nuovo bloccato.

prima che scriviate cose complicate per me (di nuovo) vi dico che devo
risolvere con il metodo più semplice possibile.



# encoding: utf-8
lista = []

while
lista.push gets.chomp
end

puts lista.sort



in parole povere dovrei scrivere delle parole che vadano a finire
nell'array lista e che poi mi vengano PUTSate fuori in oldine
alfabetico. il problema sta nel dire al while di continuare finchè non
si preme invio su una riga vuota e non riesco.
ho provate con
while lista.push.length >=1 #per far si che se la parola è meno lunga 1
finisca il ciclo, il problema sta nel fatto che il length si riferisce
alle parole dell'array e non alla parola che viene scritta dal gets.
1a45b192d0bbaf167afb43a41859e313?d=identicon&s=25 Ju Liu (Guest)
on 2014-02-05 23:48
(Received via mailing list)
Ciao Dario,

ti consiglio di provare i comandi dentro a irb, la shell ruby, cos
capisci
che cosa fanno i comandi che scrivi. Nel tuo caso, devi assegnare il
risultato di "gets.chomp" a una variable e poi controllare che quella
variabile non sia vuota:

list = []
>
> while line = gets.chomp and line.length > 0
>   list.push line
> end
>
> puts list.sort
>

    Ju

--
M.Sc. Ju Liu
Twitter: @arkh4m <http://twitter.com/arkh4m>
Skype: johnny_arkham
Card: http://zerp.ly/ju-liu
--
Societ Cooperativa weLaika
Corso Vigevano 14/B, 10154 Torino (TO), Italy
http://welaika.com - info@welaika.com


2014-02-05 Dario Di Zio <dave-the-best@hotmail.it>:
4095f049a398cb42c1ca334ab3e620bf?d=identicon&s=25 Dario Di Zio (davek3)
on 2014-02-06 12:03
Grazie mille ancora, siete davvero una fantastica community. ci
risentiamo molto presto per il prissimo problema ;D se non riesco a
tirarmene fuori da solo. byee
This topic is locked and can not be replied to.