A szétbontás azt jelenti, hogy kinyerjük egy gyűjtemény, például egy Array vagy Hash elemeit.
A szétbontott értékeket ezután ugyanabban az utasításban változókhoz rendelhetjük.
A többszörös értékadás lehetővé teszi, hogy egyetlen utasításban több változónak adjunk értéket szétbontott értékekből.
Így a kód tömörebb és olvashatóbb lehet, és úgy valósítjuk meg, hogy a hozzárendelendő változókat vesszővel választjuk el, például first, second, third = [1, 2, 3].
A splat operátort (*) és a dupla splat operátort (**) gyakran használjuk szétbontási helyzetekben.
A *<variable_name> és a **<variable_name> nem tévesztendő össze a * és a ** operátorral.
Míg a * és a ** rendre a szorzásra és a hatványozásra szolgál, addig a *<variable_name> és a **<variable_name> az összecsomagolás és a szétbontás operátora.
A többszörös értékadás lehetővé teszi, hogy egy sorban több változónak adj értéket.
Az értékek elválasztásához vesszőt (,) használj:
>> a, b = 1, 2
=> [1, 2]
>> a
=> 1
A többszörös értékadás nem korlátozódik egyetlen adattípusra:
>> x, y, z = 1, "Hello", true
=> [1, "Hello", true]
>> x
=> 1
>> y
=> 'Hello'
>> z
=> true
A többszörös értékadással elemeket cserélhetünk fel tömbökben. Ez a gyakorlat meglehetősen gyakori a rendezési algoritmusokban. Például:
>> numbers = [1, 2]
=> [1, 2]
>> numbers[0], numbers[1] = numbers[1], numbers[0]
=> [2, 1]
>> numbers
=> [2, 1]
Ezt „párhuzamos értékadásnak” is nevezik, és arra is használható, hogy elkerüljünk egy ideiglenes változót.
Ha több változó van, mint érték, a felesleges változók nil értéket kapnak:
>> a, b, c = 1, 2
=> [1, 2]
>> b
=> 2
>> c
=> nil
Rubyban lehetőség van arra, hogy egy tömb/hash elemeit külön változókba bontsuk szét. Mivel az értékek indexsorrendben szerepelnek a tömbökben, ugyanabban a sorrendben csomagolódnak ki a változókba:
>> fruits = ["apple", "banana", "cherry"]
>> x, y, z = fruits
>> x
=> "apple"
Ha vannak olyan értékek, amelyekre nincs szükség, a _ jellel jelezheted, hogy „összegyűjtve, de nem használva”:
>> fruits = ["apple", "banana", "cherry"]
>> _, _, z = fruits
>> z
=> "cherry"
Értékek szétbontása és hozzárendelése tömbökből, amelyek egy tömbön belül vannak (más néven egymásba ágyazott tömb), ugyanúgy működik, mint a sekély szétbontás, de szükség van tagolt szétbontási kifejezésre (()), hogy egyértelmű legyen az értékek kontextusa vagy pozíciója:
>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>> (a, b), (c, d) = fruits_vegetables
>> a
=> "apple"
>> d
=> "potato"
Egy egymásba ágyazott tömbnek akár csak egy részét is mélyen kicsomagolhatod:
>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>> a, (c, d) = fruits_vegetables
>> a
=> ["apple", "banana"]
>> c
=> "carrot"
Ha a szétbontásban a változók helytelenül helyezkednek el és/vagy rossz számú érték van, szintaktikai hibát kapsz:
fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
(a, b), (d) = fruits_vegetables
# syntax error, unexpected '=', expecting '.' or &. or :: or '['
((a, b), (d)) = fruits_vegetables
# syntax error, unexpected ')', expecting '.' or &. or :: or '['
Kísérletezz itt, és észre fogod venni, hogy nem a jobb oldalon elérhető értékek diktálnak, hanem az első minta. A szintaktikai hiba nem az adatszerkezethez kötődik.
*)Amikor egy tömböt szétbontasz, a splat operátorral (*) elkaphatod a „maradék” értékeket.
Ez világosabb, mint a tömb felszeletelése (ami bizonyos helyzetekben kevésbé olvasható).
Például kinyerhetjük az első elemet, majd a maradék értékeket egy új, az első elemet nem tartalmazó tömbbe rendelhetjük:
>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>> x, *last = fruits
>> x
=> "apple"
>> last
=> ["banana", "cherry", "orange", "kiwi", "melon", "mango"]
Kinyerhetjük a tömb elején és végén lévő értékeket is, miközben a középső értékeket csoportosítjuk:
>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>> x, *middle, y, z = fruits
>> y
=> "melon"
>> middle
=> ["banana", "cherry", "orange", "kiwi"]
A * operátort mély szétbontásban is használhatjuk:
>> fruits_vegetables = [["apple", "banana", "melon"], ["carrot", "potato", "tomato"]]
>> (a, *rest), b = fruits_vegetables
>> a
=> "apple"
>> rest
=> ["banana", "melon"]
Hash szétbontásaEgy hash szétbontása kicsit más, mint egy tömb szétbontása. Ahhoz, hogy egy hash-t ki tudj csomagolni, először tömbbe kell alakítanod. Különben nem lesz szétbontás:
>> fruits_inventory = {apple: 6, banana: 2, cherry: 3}
>> x, y, z = fruits_inventory
>> x
=> {:apple=>6, :banana=>2, :cherry=>3}
>> y
=> nil
Ha egy Hash-t tömbbé szeretnél alakítani, használhatod a to_a metódust:
>> fruits_inventory = {apple: 6, banana: 2, cherry: 3}
>> fruits_inventory.to_a
=> [[:apple, 6], [:banana, 2], [:cherry, 3]]
>> x, y, z = fruits_inventory.to_a
>> x
=> [:apple, 6]
Ha a kulcsokat szeretnéd kicsomagolni, használhatod a keys metódust:
>> fruits_inventory = {apple: 6, banana: 2, cherry: 3}
>> x, y, z = fruits_inventory.keys
>> x
=> :apple
Ha az értékeket szeretnéd kicsomagolni, használhatod a values metódust:
>> fruits_inventory = {apple: 6, banana: 2, cherry: 3}
>> x, y, z = fruits_inventory.values
>> x
=> 6
Az összecsomagolás lehetővé teszi, hogy több értéket egyetlen, egy változóhoz rendelt tömbben csoportosítsunk. Ez akkor hasznos, ha az értékeket szét szeretnéd bontani, módosításokat végzel rajtuk, majd az eredményeket visszacsomagolod egy változóba. Arra is lehetőséget ad, hogy összefésüléseket hajts végre két vagy több tömbön/hash-en.
*)Egy tömb összecsomagolását a splat operátorral (*) végezheted el.
Ez az összes értéket egy tömbbe csomagolja.
>> fruits = ["apple", "banana", "cherry"]
>> more_fruits = ["orange", "kiwi", "melon", "mango"]
# fruits and more_fruits are unpacked and then their elements are packed into combined_fruits
>> combined_fruits = *fruits, *more_fruits
>> combined_fruits
=> ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
**)Egy hash összecsomagolása a dupla splat operátorral (**) történik.
Ez az egyik hash összes kulcs/érték párját egy másik hashbe csomagolja, vagy két hash-t kombinál össze.
>> fruits_inventory = {apple: 6, banana: 2, cherry: 3}
>> more_fruits_inventory = {orange: 4, kiwi: 1, melon: 2, mango: 3}
# fruits_inventory and more_fruits_inventory are unpacked into key-values pairs and combined.
>> combined_fruits_inventory = {**fruits_inventory, **more_fruits_inventory}
# then the pairs are packed into combined_fruits_inventory
>> combined_fruits_inventory
=> {:apple=>6, :banana=>2, :cherry=>3, :orange=>4, :kiwi=>1, :melon=>2, :mango=>3}
*) és a dupla splat operátor (**) használata metódusokkalAmikor olyan metódust hozol létre, amely tetszőleges számú argumentumot fogad, a metódus definíciójában használhatod a *arguments vagy a **keyword_arguments formát.
A *arguments tetszőleges számú pozicionális (nem kulcs alapú) argumentum becsomagolására szolgál, a **keyword_arguments pedig tetszőleges számú kulcsargumentum becsomagolására.
A *arguments használata:
# This method is defined to take any number of positional arguments
# (Using the single line form of the definition of a method.)
>> def my_method(*arguments)= arguments
# Arguments given to the method are packed into an array
>> my_method(1, 2, 3)
=> [1, 2, 3]
>> my_method("Hello")
=> ["Hello"]
>> my_method(1, 2, 3, "Hello", "Mars")
=> [1, 2, 3, "Hello", "Mars"]
A **keyword_arguments használata:
# This method is defined to take any number of keyword arguments
>> def my_method(**keyword_arguments)= keyword_arguments
# Arguments given to the method are packed into a dictionary
>> my_method(a: 1, b: 2, c: 3)
=> {:a => 1, :b => 2, :c => 3}
Ha a definiált metódusnak nincs egyetlen kulcsargumentumhoz tartozó paramétere sem (**keyword_arguments vagy <key_word>: <value>), akkor a kulcsargumentumok egy hashbe csomagolódnak, és az utolsó paraméterhez lesznek hozzárendelve.
>> def my_method(a)= a
>> my_method(a: 1, b: 2, c: 3)
=> {:a => 1, :b => 2, :c => 3}
A *arguments és a **keyword_arguments egymással kombinálva is használható:
def my_method(*arguments, **keyword_arguments)
p arguments.sum
for (key, value) in keyword_arguments.to_a
p key.to_s + " = " + value.to_s
end
end
my_method(1, 2, 3, a: 1, b: 2, c: 3)
6
"a = 1"
"b = 2"
"c = 3"
Írhatsz argumentumokat a *arguments elé és mögé is, hogy konkrét pozicionális argumentumokat engedélyezz.
Ez ugyanúgy működik, mint egy tömb szétbontása.
Az argumentumokat meghatározott sorrendben kell elhelyezni:
def my_method(<positional_arguments>, *arguments, <positional_arguments>, <keyword_arguments>, **keyword_arguments)
Ha nem követed ezt a sorrendet, hibát kapsz.
def my_method(a, b, *arguments)
p a
p b
p arguments
end
my_method(1, 2, 3, 4, 5)
1
2
[3, 4, 5]
Pozicionális argumentumokat a *arguments elé és mögé is írhatsz:
>> def my_method(a, *middle, b)= middle
>> my_method(1, 2, 3, 4, 5)
=> [2, 3, 4]
Kombinálhatod a pozicionális argumentumokat, a *arguments, a kulcsargumentumokat és a **keyword_arguments formát:
>> def my_method(first, *many, last, a:, **keyword_arguments)
p first
p many
p last
p a
p keyword_arguments
end
>> my_method(1, 2, 3, 4, 5, a: 6, b: 7, c: 8)
1
[2, 3, 4]
5
6
{:b => 7, :c => 8}
Ha az argumentumokat rossz sorrendben írod, hibát kapsz:
def my_method(a:, **keyword_arguments, first, *arguments, last)
arguments
end
my_method(1, 2, 3, 4, a: 5)
syntax error, unexpected local variable or method, expecting & or '&'
... my_method(a:, **keyword_arguments, first, *arguments, last)
A splat operátorral (*) egy argumentumokból álló tömböt csomagolhatsz ki egy metódushívásba:
def my_method(a, b, c)
p c
p b
p a
end
numbers = [1, 2, 3]
my_method(*numbers)
3
2
1
A dupla splat operátorral (**) egy argumentumokból álló hash-t csomagolhatsz ki egy metódushívásba:
def my_method(a:, b:, c:)
p c
p b
p a
end
numbers = {a: 1, b: 2, c: 3}
my_method(**numbers)
3
2
1
A barátod, Linus mozdonyvezető, aki tehervonatokat vezet városok között. Bár a vonatok kezelésében fantasztikus, a logisztikához és a számítógépekhez már nem annyira ért. Szeretné igénybe venni a programozói segítségedet, hogy rendszerezze a vonatok adatait, és kijavítsa az útvonaladatok hibáit.
Ezt a feladatot könnyedén meg lehetne oldani szeleteléssel, indexeléssel és különféle hash-módszerekkel.
Mi viszont szeretnénk, ha az alábbi részfeladatok megoldása során a pakolást, a kicsomagolást és a többszörös értékadást gyakorolnád.
A barátod eddig minden vagon azonosítóját (ID) nyilvántartotta, de sosem tudja biztosan, hány vagont kell a rendszernek egy adott pillanatban feldolgoznia. A logisztikai program többi részének sokkal egyszerűbb lenne a dolga, ha ezek az adatok egyetlen tömbben lennének összecsomagolva.
Készíts egy generate_list_of_wagons() metódust, amely tetszőleges számú vagon-ID-t fogad.
Minden ID egy pozitív egész szám lesz.
A metódus ezután egyetlen tömbként return-ölje vissza a megadott ID-kat.
LocomotiveEngineer.generate_list_of_wagons(1, 7, 12, 3, 14, 8, 5)
# => [1, 7, 12, 3, 14, 8, 5]
Ezen a ponton már kezded megérezni, milyen adatokról van szó, és hogyan használja őket a logisztikai program. Az ID-rendszer a mozdonynak mindig az 1-es ID-t osztja ki, a vonat többi vagonja pedig egy véletlenszerűen választott, 1-nél nagyobb ID-t kap.
A barátodnak két új vagont kellett a vonathoz kapcsolnia, de elfelejtette frissíteni a rendszert! Most a vonat tömbjében az első két vagont a végére kell mozgatni, különben minden sorrend felborul.
Hogy még bonyolultabb legyen a helyzet, a barátod épp most bukkant egy második tömbre, amely látszólag hiányzó vagon-ID-kat tartalmaz. Csak arra emlékszik, hogy miután az új vagonokat átmozgattuk, a második tömb ID-it közvetlenül a kijelölt mozdony után kell elhelyezni.
Linus nagyon hálás lenne, ha kijavítanád a hibáit, és összevonnád az adatokat.
Készíts egy fix_list_of_wagons() metódust, amely két, vagon-ID-kat tartalmazó tömböt kap.
Az első tömb első két elemét helyezze át a végére, a második tömb értékeit pedig szúrja be a mozdony ID-ja (1) mögé (a jobb oldalára).
A metódus ezután return-ölje vissza a módosított tömböt.
LocomotiveEngineer.fix_list_of_wagons([2, 5, 1, 7, 4, 12, 6, 3, 13], [3, 17, 6, 15])
# => [1, 3, 17, 6, 15, 7, 4, 12, 6, 3, 13, 2, 5]
Most, hogy minden vagonadat helyes, Linus szeretné, ha frissítenéd a rendszer útvonal-információit. Egy szállítási útvonalon a vonat több különböző állomáson is megállhat, hogy rakományt vegyen fel és/vagy tegyen le. Minden út során más és más lehet ezeknek a közbenső lerakodási pontoknak a száma. A barátod szeretné, ha a rendszer útvonal-hash-ét frissítenéd minden hiányzó vagy további szállítási információval.
Készíts egy add_missing_stops() metódust, amely egy útvonal-hash-t, majd tetszőleges számú kulcsszóargumentumot fogad.
Ezek az argumentumok lehetnek egy vagy több megállót tartalmazó hash formájában, vagy tetszőleges számú stop_<number>: "city" kulcsszópárként.
A metódus ezután adja vissza az útvonal-hash-t egy további kulccsal kiegészítve, amely az összes hozzáadott megállót egy tömbben, sorrendben tartalmazza.
LocomotiveEngineer.add_missing_stops({from: "New York", to: "Miami"},
stop_1: "Washington, DC", stop_2: "Charlotte", stop_3: "Atlanta",
stop_4: "Jacksonville", stop_5: "Orlando")
# => {from: "New York", to: "Miami", stops: ["Washington, DC", "Charlotte", "Atlanta", "Jacksonville", "Orlando"]}
A megállók mindig a helyes sorrendben érkeznek, így nem kell azzal törődnöd, hogy rendezd őket.
Linus az útvonalprogramon dolgozott, és észrevette, hogy bizonyos útvonalakról hiányoznak fontos részletek. A kezdeti útvonal-információk hash formájában készültek el, és a barátod szeretné, ha ezt a hash-t kiegészítenéd mindazzal, ami hiányozhat. A rendszer minden útvonala kicsit más részleteket igényel, ezért Linus igazán egy általános megoldást szeretne.
Készíts egy extend_route_information() nevű metódust, amely két hash-t fogad.
Az első hash tartalmazza azokat a kiindulási és célvárosokat, amelyek között a vonat útvonala halad.
A második hash további útvonal-részleteket tartalmaz, például a vonat sebességét, hosszát vagy a hőmérsékletet. A metódusnak egy összevont hash-t kell visszaadnia az összes útvonal-információval.
A második hash a példában láthatóktól eltérő vagy annál több tulajdonságot is tartalmazhat.
LocomotiveEngineer.extend_route_information({"from": "Berlin", "to": "Hamburg"}, {"length": "100", "speed": "50"})
# => {"from": "Berlin", "to": "Hamburg", "length": "100", "speed": "50"}
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Ruby nyelvet 21 fogalom121 feladat segítségével, valódi emberi mentorálással, mindez ingyen.