Làm việc với vòng lặp trong Ruby
Bài đăng này đã không được cập nhật trong 8 năm
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:
http://ruby-doc.org/core-2.2.0/Enumerator.html
http://www.zenruby.info/2016/06/ruby-iterators-enumerators-enumerable.html
All rights reserved