Problema semplice ruby

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

Ciao Dario,

2014-02-05 Dario Di Zio [email protected]:

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?

io lo so! io lo so!

posso rispondere?

che poi la definizione giusta e’:

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

credo

Rambaldi, lei no che è in punizione.

[image: Inline images 1]

2014-02-05 Davide R. [email protected]:

puoi barare e vedere se l’ultimo giorno di febbraio per ogni anno è il
29.

2014-02-05 Davide R. [email protected]:

Perch non

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

?

2014-02-05 Dario Di Zio [email protected]:

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.

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

On 05 Feb 2014, at 16:22, Dario Di Zio [email protected] 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
:slight_smile:

Davide R

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 :smiley: (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

2014-02-05 Dario Di Zio [email protected]:

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 (
    Using “and” and “or” in Ruby - avdi.codes)
  2. usa gli spazi tra gli operatori “x <= y” al posto di “x<=y”

Have fun :slight_smile:

encoding: utf-8

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

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

On 05 Feb 2014, at 19:23, Ju Liu [email protected] 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!

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 :slight_smile:

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 - [email protected]

2014-02-05 maurizio de magnis [email protected]:

ora però vogliamo la gemma :wink:

2014-02-05 Davide R. [email protected]:

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 :slight_smile:

Ciao Ju :slight_smile:

mmh, posso fare un raise ExcessiveTrickiness.new? :wink:

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 [email protected]:

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.

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 - [email protected]

2014-02-05 Dario Di Zio [email protected]: