Tablourile sunt una dintre structurile fundamentale ale programării. Abilitatea de a manipula și citi rapid date din ele este vitală pentru succesul în construirea de lucruri cu computere. Iată șase metode de care nu poți face lipsă.

Hartă / Fiecare

Aceste două metode sunt foarte asemănătoare. Acestea vă permit să parcurgeți „fiecare” articol dintr-o matrice și să faceți ceva pentru el.

Verificați câteva coduri:

array = [1, 2, 3]
effects = array.each{|x| # create record from x }
added = array.map{ |x| x + 2 }

Dacă citim din added, vom lua [3, 4, 5]. Dacă citim din effects, vom primi totuși [1, 2, 3]. Iată diferența dintre aceste două: .map va returna un nou matrice modificată, întrucât .each va returna matricea originală.

Efecte secundare pe hartă

Dacă ești obișnuit cu programarea funcțională, Ruby .map ar putea părea foarte ciudat. Uită-te la acest exemplu. Am un simplu Event curs în proiectul meu:

# we create an array of records
2.3.0 :025 > array = [e, e2, e3]
 => [#<Event id: 1, name: nil>, #<Event id: 2, name: nil">, #<Event id: 3, name: nil>]
# so far so good
2.3.0 :026 > new_array = array.map{|e| e.name = "a name"; e}
 => [#<Event id: 1, name: "a name">, #<Event id: 2, name: "a name">, #<Event id: 3, name: "a name">]
# uh-oh, that ain't right
2.3.0 :027 > array
 => [#<Event id: 1, name: "a name">, #<Event id: 2, name: "a name">, #<Event id: 3, name: "a name">]

Ne-am putea aștepta să lucrăm cu un fel de copie a înregistrărilor noastre în matrice, dar nu suntem. Asta este doar pentru a spune: fii atent. Puteți crea cu ușurință efecte secundare în .map funcții.

Ok stai ușor, asta a fost cel greu. Navigare lină de aici înainte.

Selectați

.select vă permite să „găsiți” un element dintr-o matrice. Trebuie să dai .select o funcție care returnează adevărat sau fals, deci știe dacă „păstrează” sau nu un element matrice.

2.3.0 :028 > array = ['hello', 'hi', 'goodbye']
2.3.0 :029 > array.select{|word| word.length > 3}
 => ["hello", "goodbye"]

Un exemplu ușor mai complex, care se apropie probabil de modul în care ați folosi de fapt acest lucru. Să aruncăm .map la sfârșit pentru o măsură bună:

2.3.0 :030 > valid_colors = ['red', 'green', 'blue']
2.3.0 :031 > cars = [{type: 'porsche', color: 'red'}, {type: 'mustang', color: 'orange'}, {type: 'prius', color: 'blue'}]
2.3.0 :032 > cars.select{ |car| valid_colors.include?(car[:color]) }.map{ |car| car[:type]}
=> ["porsche", "prius"]

Da, oameni buni, vă puteți alătura acestor metode pentru a exercita o putere inimaginabilă. Ok, probabil îți poți imagina, dar este totuși cool.

Sintaxă chiar mai curată: .map (&: method)

Dacă am fi lucrat cu obiecte auto și nu doar cu un hash simplu, am fi putut folosi o sintaxă mai curată. Voi folosi un alt exemplu pentru concizie. Poate că pregătim această listă de mașini pentru a fi trimise într-un API și trebuie să generăm JSON. Putem folosi .to_json metodă:

# using regular map syntax
2.3.0 :047 > cars.select{ |car| valid_colors.include?(car[:color]) }.map{|car| car.to_json}
 => ["{"type":"porsche","color":"red"}", "{"type":"prius","color":"blue"}"]
# using the cleaner syntax
2.3.0 :046 > cars.select{|car| valid_colors.include?(car[:color]) }.map(&:to_json)
 => ["{"type":"porsche","color":"red"}", "{"type":"prius","color":"blue"}"]

Respinge

Respingerea este yinul către .selectYang:

2.3.0 :048 > cars.reject{|car| valid_colors.include?(car[:color]) }.map{|car| car[:type]}
 => ["mustang"]

In loc de selectarea pentru elementele matrice pe care le dorim, o vom face respinge tot ceea ce nu face ca funcția noastră să revină adevărată. Amintiți-vă că funcționează în interiorul respingerii noastre este ceea ce determină dacă elementul matricei va fi returnat sau nu – dacă este adevărat, elementul este returnat, altfel nu.

Reduce

Reduce are o structură mai complexă decât celelalte metode ale noastre de matrice, dar este, în general, utilizată pentru lucruri destul de simple în Ruby – în special lucruri matematice. Vom lua o matrice, apoi vom executa o funcție pe fiecare element din matricea respectivă. De data aceasta, ne pasă de ceea ce se returnează din alte elemente matrice. De obicei, adăugăm o grămadă de numere:

2.3.0 :049 > array = [1, 2, 3]
2.3.0 :050 > array.reduce{|sum, x| sum + x}
 => 6

Rețineți că putem lucra cu șiruri în același mod:

2.3.0 :053 > array = ['amber', 'scott', 'erica']
2.3.0 :054 > array.reduce{|sum, name| sum + name}
 => "amberscotterica"

Acest lucru ar putea fi util dacă ne uităm la o grămadă de înregistrări de lucru. Dacă trebuie să adunăm totalul de ore lucrate sau dacă dorim să aflăm suma tuturor donațiilor luna trecută. O ultimă notă despre .reduce. Dacă lucrați cu altceva decât numerele vechi obișnuite (sau șirurile), va trebui să includeți o valoare de pornire ca argument:

array = [{weekday: 'Monday', pay: 123}, {weekday: 'Tuedsay', pay: 244}]
array.reduce(0) {|sum, day| sum + day[:pay]}
 => 367
array.reduce(100) {|sum, day| sum + day[:pay]}
 => 467

Există, desigur, modalități mai avansate de utilizare .reduce dar aceasta este o mulțime pentru a începe.

A te alatura

Arunc înăuntru .join ca bonus pentru că este atât de util. Să ne folosim din nou de mașini:

2.3.0 :061 > cars.map{|car| car[:type]}.join(', ')
 => "porsche, mustang, prius"

.join este foarte asemănător .reduce cu excepția faptului că are o sintaxă super-curată. Este nevoie de un argument: un șir care va fi inserat între toate elementele matricei. .joincreează un șir lung din orice îi oferiți, chiar dacă matricea dvs. este o grămadă de lucruri care nu sunt șir:

2.3.0 :062 > cars.join(', ')
 => "{:type=>"porsche", :color=>"red"}, {:type=>"mustang", :color=>"orange"}, {:type=>"prius", :color=>"blue"}"
2.3.0 :065 > events.join(', ')
 => "#<Event:0x007f9beef84a08>, #<Event:0x007f9bf0165e70>, #<Event:0x007f9beb5b9170>"

De ce nu aruncăm totul împreună

Să folosim toate dintre metodele matrice din acest post împreună! Zece zile de treburi și este întâmplător cât va dura fiecare. Vrem să știm timpul total pe care îl vom petrece pentru treburi. Aceasta presupunând că ne relaxăm și ignorăm tot ceea ce durează mai mult de 15 minute. Sau amânați până în altă zi orice se poate face în mai puțin de 5:

days = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
days.map{|day| day.odd? ? 
  {task: 'dishes', minutes: Random.rand(20)} :
  {task: 'sweep', minutes: Random.rand(20)}}
  .select{|task| task[:minutes] < 15}
  .reject{|task| task[:minutes] < 5}
  .reduce(0) {|sum, task| sum + task[:minutes]}

Răspunsul meu este irelevant, deoarece veți obține minute aleatorii diferite pentru sarcinile dvs. Dacă oricare dintre acestea este proaspăt sau confuz, lansează o consolă Ruby și dă-i un vârtej.

PS: Asta ? : afaceri pe .map se numește a ternary. Este doar o afirmație if-else. Îl folosesc aici doar ca să fiu elegant și să obțin totul pe o singură linie. Ar trebui să evitați un astfel de ternar complicat în propria bază de cod.

Ne vedem data viitoare!