07/09/2018, 16:04

Phải học Enumerable khi học Ruby

Enumerable trong Ruby tương đương với collection trong Java. Nói theo thuật ngữ Java, thì Enumerable là interface được những class như Array, Hash, Set implement. Còn nói theo thuật ngữ Ruby, thì module Enumerable được những class trên include. Việc rành rẽ các phương thức trong Enumerable là ...

Enumerable trong Ruby tương đương với collection trong Java. Nói theo thuật ngữ Java, thì Enumerable là interface được những class như Array, Hash, Set implement. Còn nói theo thuật ngữ Ruby, thì module Enumerable được những class trên include.

Việc rành rẽ các phương thức trong Enumerable là bước tiến lớn khi học Ruby. Nó cũng là chuyển tiếp quan trọng giúp bạn dần tư duy theo phong cách functional, là phong cách rất mốt hiện tại. Rành rẽ chúng xong, khi học sang Java 8, Scala, Erlang v.v. bạn sẽ thấy rất thoải mái, vì chúng cũng có mặt trong thư viện chuẩn của các ngôn ngữ này.

Bài viết này giới thiệu vài method tiện dụng của Enumerable, nếu dùng chương trình sẽ súc tích và sáng sủa. Phần ví dụ dùng array cho thống nhất, nói chung chúng vẫn đúng nếu thay array bằng hash hay cái gì đó đã include module này.

map/collect

Biến array a1 thành array a2 có cùng số phần tử, dùng map (có alias là collect) rất tiện. Ý tưởng của nó chính là phép ánh xạ y = f(x) trong toán học, để biến từng phần tử x của a1 thành phần tử y của a2.

Ví dụ từ a1 chứa tên ảnh, ta muốn tạo a2 chứa URL có dạng y = http://my/path/x. Nếu chỉ quen với C, ta viết như sau:

a1 = ['asian.jpg', 'ebony.jpg']

a2 = [] # Initialize
a1.each do |e|
a2 << "http://my/path/#{e}"
end

Nếu dùng map:

a1 = ['asian.jpg', 'ebony.jpg']
a2 = a1.map { |e| "http://my/path/#{e}" }

Thần chú: Biến array thành array cùng kích thước: dùng map

select/find_all

Muốn chọn những phần tử thoả mãn điều kiện nào đó từ array, ta dùng select (có alias là find_all). Trái nghĩa với select là reject.

a = [1, 2, 3, 4]
evens = a.select { |e| i%2 == 0 }

Thần chú: Biến array thành array nhỏ hơn: dùng select

inject

Khi muốn tạo giá trị scalar (1 chiều) từ các phần tử của array (đa chiều), ví dụ để tính tổng của các phần tử, thường ta viết như sau:

a = [1, 2, 3]

sum = 0
a.each do |e|
sum += e
end

Nếu dùng inject:

a = [1, 2, 3]
sum = a.inject(0) { |tmp, e| tmp += e }

Thần chú: Kết hợp tất cả phần tử của array thành một biến duy nhất: dùng inject

join

Thật ra join chỉ có trong Array. Rất nhiều khi ta muốn nối các phần tử của array lại thành một chuỗi, cách nhau bởi dấu phẩy chẳng hạn. Nếu tự viết thì rất lắt nhắt vì dấu phẩy phải nằm xen kẽ giữa các phần tử.

Dùng join thì ta chỉ cần viết đơn giản như sau:

a = [1, 2, 3]
s = a.join(", ") # => "1, 2, 3"

Thần chú: Nối tất cả phần tử của array thành chuỗi: dùng join

any? và all?

Khi muốn kiểm tra trong tập hợp có ít nhất một phần tử thỏa mãn tính chất nào đó hay không, ta dùng any?. Khi muốn kiểm tra xem tất cả phần tử có thỏa mãn tính chất nào đó hay không, ta dùng all?

a = [1, 2, 3]
at_least_less_than_2 = a.any? { |e| e < 2 }
all_less_than_2 = a.all? { |e| e < 2 }

Tóm lại, nếu cần hơn 1, 2 dòng để thao tác trên array, hãy tham khảo tài liệu của Enumerable gấp.

0