Ruby po kapkách – úkoly a řešení (2.)
V tomto článku se opět budeme věnovat úkolům, na nichž si můžete otestovat čerstvě nastudované možnosti jazyka Ruby. Začněme řešením minulého zadání.
V prvním úkolu jsme předpokládali, že uživatel zadá na STDIN
buď slovo „ano“ nebo slovo „ne“ a stiskne enter (pro zjednodušení nebylo třeba ošetřovat žádné jiné stavy ani potenciální chyby). Cílem bylo dopsat chybějící první část následujícího kódu a najít řešení, kde by se nepoužila podmínka. Volitelnou součástí bylo doplnit situaci, kdy není zadáno ani jedno ze zmíněných slov.
…
if p
puts „Bylo to ANO!“
else
puts „Bylo to NE!“
end
Když se na fragment kódu podíváme, můžeme problém přeformulovat. Potřebujeme dosáhnout toho, aby na základě nějaké hodnoty načtené ze vstupu byla v proměnné p hodnota true
nebo false
. Respektive aby to byla hodnota, která se vyhodnotí jako pravda či nepravda v podmínce. Pro tento účel nám vyhovuje již osvědčená metoda index
.
p = gets.index(‚ano‘)
if p
puts „Bylo to ANO!“
else
puts „Bylo to NE!“
end
V případě, že návratová hodnota gets
obsahuje slovo „ano“, bude do p uložena 0 jako index znaku, na kterém začíná hledaný řetězec. 0 se vyhodnocuje v podmínce jako true
. Podle zadání byl jediný jiný možný vstup slovo „ne“. V takovém případě vrátí index
nil
, který se vyhodnotí v podmínce jako nepravda. Podívejme se ještě na jiné možné řešení, které je obecnější a rozeznává i vstup, který neodpovídá ani jednomu známému slovu.
t = Hash.new(‚neznámé slovo‘)
t[‚ano‘] = ‚ANO‘
t[‚ne‘] = ‚NE‘
x = gets.chop
puts „Bylo to #{t[x]}!“
Tento program využívá hash jako překladovou tabulku. Defaultní hodnota hashe ošetří všechna nedefinovaná slova. Povšimněte si ještě volání metody chop
na výstup z gets
. Tato metoda totiž načítá celý řádek vstupu včetně znaku (nebo znaků) označujícího konec řádku. Metoda chop
tento koncový znak z řetězce odstraní.
Druhým úkolem bylo vytvořit filtr, který by načítal slovník a vypisovat palindromy – slova, která jsou stejná, i když je čteme odzadu. Slovník byl definován jako textový soubor, kde je na každém řádku jedno slovo. Řešení je velmi jednoduché.
while line = gets.chop
puts line if line == line.reverse
end
Pro správnou funkci je třeba opět použít chop
. Poslední úkol byl malinko těžší, ale s rozpomenutím se na školní matematiku by mělo být možné ho s dosavadními znalostmi Ruby vyřešit. Zadáním bylo napsat program, který vypíše všechna prvočísla menší než 100. Jedno možné řešení je ukázáno níže.
2.upto(100) do |n|
p = 2
q = (n ** 0.5).to_i + 1
while p != q
break if n % p == 0
p += 1
end
puts n if p == q
end
Víme, že prvočísla jsou větší než jedna a shora máme omezení také zadáno. Vnější smyčka programu tedy postupně do proměnné n načítá čísla od 2 do 100. Vnitřní smyčka pak zkouší zbytek po dělení až do druhé odmocniny a předčasně skončí, pokud nalezne dělitele, kterým je aktuální n dělitelné beze zbytku. Nejvyšší vyzkoušený dělitel je uchován v proměnné p. Pokud se na konci vnitřního cyklu rovná nejvyšší vyzkoušený dělitel druhé odmocnině testovaného čísla, je číslo vypsáno jako prvočíslo. Získání druhé odmocniny jsme zatím neuváděli. Pomohli jsem si proto umocňovacím operátorem a mocněním na jednu polovinu. Aby algoritmus fungoval v mezním případě (ponecháme na čtenáři, aby si uvědomil, který to je), je k druhé odmocnině převedené na celé číslo ještě přičtena jednička.
Za zmínku stojí ještě zápis bloku předaného metodě upto
. Protože je blok dlouhý několik řádků, velí konvence uzavřít ho mezi klíčová slova do
a end
namísto složených závorek. Oba zápisy jsou však jinak ekvivalentní.
Prvním dnešním zadáním úkolu bude přepsat příklad s prvočísly za pomocí čerstvých znalostí metod, které jsou dostupné pro všechny Enumerable
objekty. K tomu si ukážeme ještě dvě navíc, které umožňují testovat, zda zadaný blok vrací hodnotu true
pro všechny nebo aspoň pro jeden z prvků kolekce. (K řešení nejsou tyto metody nutné, ale mohou se hodit.)
irb(main):001:0> [1, 2, 3].all? { |e| e > 1 }
=> false
irb(main):002:0> [1, 2, 3].any? { |e| e > 1 }
=> true
Funkcionalitu těchto metod by bylo možné implementovat pomocí metody inject
. To je zároveň zadání druhého úkolu. Pokuste se také přijít na to, jaké omezení má implementace pomocí inject
oproti nativní implementaci. Napovědět by vám měl následující kousek kódu.
irb(main):003:0> [1, 2, 3].any? { |e| puts e > 1; e }
false
=> true
Poslední dnešní úloha spočívá v transformaci pole. Předpokládejme, že máme vstupní pole, které obsahuje prvky v podobě celých čísel od 0 do 9. Pole může vypadat například takto: [1, 3, 1, 5, 5, 8, 2, 9]. Vytvořte kód, který toto pole převede na pole, kde pro každý index od 0 do 9 je hodnotou, kolikrát se tento index objevil jako hodnota v prvním poli. Pro náš příklad bude tedy výsledek: [0, 2, 1, 1, 0, 2, 0, 0, 1, 1] (to znamená, že 0 se v prvním poli neobjevila ani jednou, 1 dvakrát, 2 jedenkrát atd.). Snažte se nalézt krátké, ale čitelné řešení.
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Proč je důležité tvořit obsah na váš web?
29. srpna 2024 -
Rychlost serveru: Klíč k lepšímu umístění ve vyhledávačích
7. června 2024 -
Zvýšení výkonu WiFi signálu: Jak a proč používat WiFi zesilovače
28. června 2023 -
Windows App: Pracujte odkudkoliv, kdykoliv
3. listopadu 2024
Nejnovější
-
Výkonný a kompaktní: ASOME Max Studio s výjimečným poměrem cena/výkon
11. listopadu 2024 -
Šokující data od Microsoftu: Kyberútoky rostou o stovky procent!
8. listopadu 2024 -
Chcete jedinečnou doménu? Objevte koncovky FOOD, MEME a MUSIC!
7. listopadu 2024 -
OpenAI představilo novou funkci ChatGPT Search
6. listopadu 2024