Làm việc với vòng lặp trong Ruby

Trong Ruby, làm việc với vòng lặp là một công việc thường xuyên và không thể thiếu trong bất kì một project nào. Bài viết này xin được giới thiệu một số method làm việc với vòng lặp hữu ích mà có thể bạn chưa dùng đến

I, step

    3.step(10, 2) { |n| print "#{n} " }

Method này được dùng trong vòng lặp các số Integer. Nó sẽ chạy từ 3 đến 10, với mỗi bước chạy là 2. Kết quả sẽ in ra các số: 3, 5, 7, 9

II, reverse_each

Method này làm ngược lại với method each, duyệt một range theo chiều từ cao xuống thấp

    range = (3..10)
    r.reverse_each { |n| print "#{n} " }
    => 10 9 8 7 6 5 4 3 => 3..10

III, each_char và each_line

Method này làm việc trên các String. Để duyệt theo từng kí tự hay theo từng dòng trên các string

    s = "What is \nthe sound \nof silence?"
    s.each_char { |x| puts x }
    #output
    W
    h
    a
    t

    i
    s

    t
    h
    e

    s
    o
    u
    n
    d

    o
    f

    s
    i
    l
    e
    n
    c
    e
    ?
    => "What is \nthe sound \nof silence?"
    s.each_line { |x| puts x }
    #output
    What is
    the sound
    of silence?

IV, Một số method trên đối tượng Enumerator

Giả sử ta có một enumerator:

    e =  [ 1, 2, 3, 4, 5 ].each  # Output: => #<Enumerator: [1, 2, 3, 4, 5]:each>
    e.next
    =>1
    e.peek
    =>2
    e.next
    =>2

Method next và peek đều trả về phần tử tiếp theo của enumerator, khác nhau ở chỗ next sẽ move vị trí con trỏ bên trong enumerator lên phía trước còn peek thì không

    e.rewind
    => 1

Đặt lại vị trí con trỏ bên trong về vị trí của phần tử đầu tiên của enumerator. Các method next_values và peek_values tương tự như next và peek, chỉ khác nhau ở chỗ giá trị trả về được gói trong một mảng.

V, none?

Ngược lại với method any?. Trả về true nếu block trả về false cho tất cả các phần tử của mảng. Nếu không có block, trả về true nếu tất cả các phần từ là false hoặc nil

    [ "foo", "baar" ].none? { |x| x.length < 3 } => true
    [false, nil].none? => true

VI, count

Method count dùng để đếm các phần tử thỏa mãn điều kiện nào đó trong một tập hợp

    a = [ "foo", "bar", "baz", "foo" ]
    a.count("foo")
    => 2
    a = [ 2, 5, 6, 8, 12 ]
    a.count {|i| i.even?} # Output: => 4

VII, group_by

Trả về một hash, với các key là kết quả trả về từ một block, còn value là mảng các phần tử trong enum tương ứng với key

    (1..6).group_by {|i| i%3}   #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}

Trả về phần tử và số lần xuất hiện của nó trong một mảng:

    arr = [ "foo", "bar", "baz", "foo", "foo", "baz" ] # Set up test array
    Hash[arr.group_by(&:itself).map {|key, value| [key, value.size] }]
    # Output: => {"foo"=>3, "bar"=>1, "baz"=>2}

VIII, find_all

Tương tự như method select, chỉ có điều kết quả trả về luôn và một mảng

    h = { a: 1, b: 2, c: 3 }

    h.find_all { true } # => [[:a, 1], [:b, 2], [:c, 3]]
    h.select { true } # => {:a=>1, :b=>2, :c=>3}

IX, grep_v

Ngược lại với grep, trả về một mảng gồm các phần tử không thỏa mãn pattern

    [ "foo", "bar", "baz", "qux" ].grep_v(/ba/) # Output: => ["foo", "qux"]

X, drop_while và take_while

drop_while và take_while tương tự như method reject và select, ngoại trừ việc chúng sẽ dừng ngay vòng lặp và trả về ngay kết quả khi gặp giá trị đầu tiên không thỏa mãn

    arr = [1, 2, 3, 4, 5, 6, 1, 2, 3, 8]
    arr.take_while { |a| a < 4 }  # Output: => [1, 2, 3]
    arr.drop_while { |a| a < 3 }  # Output: => [3, 4, 5, 6, 1, 2, 3, 8]

XI, reduce

Nhóm các phần tử bằng phép toán nhị phân

    [ 2, 3, 5 ].reduce { |sum, n| sum + n }  # Output: => 10
    [ 2, 3, 5 ].reduce(:+)  # Output: => 10
    [ 2, 3, 5 ].reduce(:*)  # Output: => 30

XII, max_by, min_by

Trả về phần tử có giá trị lớn nhất, nhỏ nhất thỏa mãn block

    [ "zen", "zazen", "liberation" ].max_by { |x| x.length} # Output: => "liberation"

Trên đây là một số method hữu ích được sử dụng với các vòng lặp trong Ruby. Việc sử dụng linh hoạt các method có sẵn sẽ giúp code của chúng ta đẹp và mượt hơn. Thanks for read!

Nguồn:

apidock.com

http://ruby-doc.org/core-2.2.0/Enumerator.html

http://www.zenruby.info/2016/06/ruby-iterators-enumerators-enumerable.html