Kurzusok
/
Ruby
Ruby
/
Tanterv
/
Többszörös értékadás és szétbontás
Tö

Többszörös értékadás és szétbontás ebben a kurzusban: Ruby

1 feladat

A(z) Többszörös értékadás és szétbontás fogalomról

A szétbontás egy gyűjtemény, például egy Array vagy Hash elemeinek kinyerését jelenti. A szétbontott értékek ezután ugyanazon utasításon belül változókhoz rendelhetők.

A többszörös értékadás segítségével egyetlen utasításban több változónak is adhatunk értéket, szétbontva ezzel az értékeket. Így a kód tömörebb és olvashatóbb lehet, ráadásul az értékadandó változókat csak vesszővel kell elválasztani egymástól, 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 splat operátor (*) használatával több tömböt egyetlen tömbbé fűzhetünk össze, ha mindegyiket szétbontjuk egy új, közös tömbben. A dupla splat operátor (**) használatával több hash-t egyetlen hash-be fűzhetünk össze, ha mindegyiket szétbontjuk egy új, közös hash-ben. Ez a szintaxis arra szolgál, hogy megkülönböztessük egymástól azt az esetet, amikor pozicionális argumentumként több értéket fogadunk el, attól, amikor tetszőleges számú kulcsszó-argumentumot fogadunk el.

Ha a splat operátort (*) gyűjtemény nélkül használjuk, több értéket csomagol be (azaz állít össze) egyetlen tömbbé. Ezt gyakran használjuk a többszörös értékadásban arra, hogy minden »megmaradó« elemet, amelyhez nem tartozik külön értékadás, egyetlen változóba gyűjtsünk.

Rubyban gyakori, hogy ezt a szétbontó/összeállító viselkedést akkor használjuk, amikor olyan metódusokat hívunk meg vagy definiálunk, amelyek tetszőleges számú pozicionális vagy kulcsszó-argumentumot fogadnak el. Gyakran láthatod, hogy ezeket az argumentumokat így definiálják: def some_method(*arguments, **keyword_arguments), és így adják át őket: some_method(*some_array, **some_hash).

Caution

A *<variable_name> és a **<variable_name> nem tévesztendő össze a * és a ** operátorral. Míg a * a szorzásra, a ** pedig a hatványozásra szolgál, addig a *<variable_name> és a **<variable_name> összeállítási és szétbontási operátorként működik.

Többszörös értékadás

A többszörös értékadással egyetlen sorban több változónak is adhatsz értéket. Az értékek elválasztásához használj vesszőt (,):

>> 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 tömbök elemeit is felcserélhetjük. Ez a gyakorlat meglehetősen elterjedt 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]
Note

Ezt »párhuzamos értékadás« néven is szokás emlegetni, és használatával elkerülhető egy ideiglenes változó bevezetése.

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

Ha több érték van, mint változó, a felesleges értékeket a rendszer figyelmen kívül hagyja:

>> a, b, c = 1, 2, 3, 4
>> b
=> 2
>> c
=> 3

Szétbontás

Rubyban lehetőség van arra, hogy a tömbök/hash-ek elemeit külön változókba bontsuk szét. Mivel a tömbökben az értékek indexsorrendben követik egymást, ugyanabban a sorrendben kerülnek a változókba:

>> fruits = ["apple", "banana", "cherry"]
>> x, y, z = fruits
>> x
=> "apple"

Ha vannak olyan értékek, amelyekre nincs szükség, használhatod a _ jelet annak jelzésére, hogy az érték »összegyűjtve, de nem használva«:

>> fruits = ["apple", "banana", "cherry"]
>> _, _, z = fruits
>> z
=> "cherry"

Mély szétbontás

Ha egy tömbön belüli tömbökből (ezt egymásba ágyazott tömbnek is nevezik) bontunk ki értékeket és rendelünk változókhoz, az ugyanúgy működik, mint a sekély szétbontás, de a határolt szétbontó kifejezésre (()) is szükség van ahhoz, 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 helyen és/vagy helytelen számban szerepelnek, szintaxishibá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

Kísérletezz itt egy kicsit, és észre fogod venni, hogy a minta az elsődleges, nem pedig a jobb oldalon elérhető értékek. A szintaxishiba nem az adatszerkezethez kötődik.

Tömb szétbontása az egyszeres splat operátorral (*)

Amikor [egy tömböt szétbontasz][decomposition], a splat operátorral (*) elkaphatod a »megmaradó« értékeket. Ez áttekinthetőbb, mint a tömb felszeletelése (ami bizonyos helyzetekben kevésbé olvasható). Például kinyerhetjük az első elemet, majd a megmaradó értékeket egy új, az első elemet nem tartalmazó tömbbe tehetjük:

>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>> x, *last = fruits
>> x
=> "apple"
>> last
=> ["banana", "cherry", "orange", "kiwi", "melon", "mango"]

A tömb elején és végén lévő értékeket is kinyerhetjük, miközben a középső értékeket egy csoportba gyűjtjük:

>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>> x, *middle, y, z = fruits
>> y
=> "melon"
>> middle
=> ["banana", "cherry", "orange", "kiwi"]

A *-ot 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"]

Egy Hash szétbontása

Egy hash szétbontása kicsit másképp működik, mint egy tömb szétbontása. Ahhoz, hogy egy hash-t ki tudj csomagolni, először tömbbé kell alakítanod. Különben nem történik 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

Egy Hash tömbbé alakításához 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

Összeállítás

Az összeállítás során több értéket csoportosítunk egyetlen tömbben, amelyet egy változóhoz rendelünk. Ez akkor hasznos, ha az értékeket szét szeretnéd bontani, módosítasz rajtuk, majd az eredményt összeállítva visszaírod egy változóba. Arra is lehetőséget ad, hogy két vagy több tömböt/hash-t összefésülj.

Tömb összeállítása a splat operátorral (*)

Egy tömb összeállításához a splat operátort (*) használhatod. Ez az összes értéket egyetlen tömbbé 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"]

Hash összeállítása a dupla splat operátorral (**)

Egy hash összeállításához a dupla splat operátort (**) használhatod. Ez az egyik hash összes kulcs/érték párját egy másik hash-be csomagolja, vagy két hash-t fűz ö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}

A splat operátor (*) és a dupla splat operátor (**) használata metódusokkal

Összeállítás metódusparaméterekkel

Amikor olyan metódust hozol létre, amely tetszőleges számú argumentumot fogad el, 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 kulcsszavas) argumentumot csomagol be, a **keyword_arguments pedig tetszőleges számú kulcsszó-argumentumot.

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 kulcsszó-argumentumokhoz tartozó paramétere (**keyword_arguments vagy <key_word>: <value>), akkor a kulcsszó-argumentumok egy hash-be csomagolódnak, és az utolsó paraméterhez rendelődnek.

>> 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 együtt 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"

Az argumentumokat a *arguments elé és mögé is írhatod, hogy meghatározott pozicionális argumentumaid legyenek. Ez ugyanúgy működik, mint egy tömb szétbontása.

Caution

Az argumentumokat egy meghatározott sorrendben kell elhelyezni:

def my_method(<positional_arguments>, *arguments, <positional_arguments>, <key-word_arguments>, **keyword_arguments)

Ha nem tartod be 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]

Pozicionális argumentumokat, *arguments-t, kulcsszó-argumentumokat és **keyword_arguments-t is kombinálhatsz:

>> 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 le, hiba lesz belőle:

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)

Szétbontás metódushívásokhoz

A splat operátorral (*) egy argumentumokat tartalmazó 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 argumentumokat tartalmazó 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
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg

Tanuld meg a(z) Többszörös értékadás és szétbontás fogalmat