Các phương thức thường dùng với mảng trong Ruby
Bài đăng này đã không được cập nhật trong 7 năm
Chúng ta làm việc với mảng (array
) gần như là hàng ngày. Mảng rất dễ sử dụng và gần như không có vấn đề gì khó nhằn cả. Tuy nhiên có một số phương thức (method
) khá là thú vị và tiện lợi mà mình muốn tổng hợp trong bài viết này.
Hãy bắt đầu với một mảng
arr = [1, 2, 3]
arr[9] = 'foo'
p arr # => [1, 2, 3, nil, nil, nil, nil, nil, nil, "foo"]
Ruby sẽ tự động điều chỉnh chiều dài của mảng và thay những phần tử còn thiếu bằng giá trị nil
Tạo mảng
arr = Array.new # => []
Nó cũng giống như viết arr = []
. Chúng ta có thể quy định kích thước và giá trị mặc định cho mảng bằng cách
arr = Array.new(3, 'foo') # => ["foo", "foo", "foo"]
arr[6] = 'bar'
p arr # => ["foo", "foo", "foo", nil, nil, nil, "bar"]
Như chúng ta thấy Ruby đã gán giá trị "foo" cho các thành phần của mảng khi khởi tạo. Tuy nhiên, khi cần thay đổi độ dài của mảng, Ruby sẽ dùng giá trị nil
làm giá trị mặc định.
Chúng ta có thể dùng block để tạo giá trị cho mảng
arr = Array.new(3) { |i| "item-#{i}" }
p arr # => ["item-0", "item-1", "item-2"]
Bởi vì khi khởi tạo, các giá trị của mảng có cùng chung một giá trị mặc định, nên ta có thể gặp phải vấn đề sau
arr = Array.new(2, Hash.new)
p arr # => [{}, {}]
arr[0][:foo] = 'bar'
p arr # => [{:foo=>"bar"}, {:foo=>"bar"}]
Thật thú vị khi ta chỉ thay đổi giá trị đầu tiên trong mảng nhưng nó cũng thay đổi luôn giá trị thứ hai. Đó là bởi vì chúng được xem như cùng một hash
Để giải quyết vấn đề này, chúng ta nên tạo một hash
cho mỗi phần tử của mảng
arr = Array.new(2) { Hash.new }
p arr # => [{}, {}]
arr[0][:foo] = 'bar'
p arr # => [{:foo=>"bar"}, {}]
Giờ mỗi phần của từ mảng được coi như một mảng riêng. Nếu bạn muốn gói vài giá trị vào trong một mảng, bạn có thể sử dụng
arr = Array(3) # => [3]
arr = Array([1,2,3]) # => [1,2,3]
Cắt (Slicing)
Mảng bao gồm cả module Enumerable
, vì vậy nó có tất cả các phương thức tiện lợi, giống như: find
, map
, inject
,...
Để cắt, lấy một phần tử trong mảng, ta dùng phương thức slide
hoặc []
, nó hoạt động giống nhau
arr = [1,2,3,4]
arr[0] # => 1
arr[20] # => nil
Có thể truyền thêm biến thứ 2 quy định độ dài
arr = [1,2,3,4]
arr[0, 2] # => [1, 2]
Ở đây hiểu là lấy 2 phần tử bắt đầu từ phần tử được đánh thứ tự là 0
Có thể truyền vào một khoảng
arr = [1,2,3,4]
p arr[0..2] # => [1, 2, 3]
Tất cả mọi trường hợp đều trả về một mảng mới, nhưng nếu bạn muốn thay đổi mảng hiện tại, dùng phương thức slide!
arr = [1, 2, 3]
arr.slice!(1, 2) # => [2, 3]
p arr # => [1]
Ở đây ta đã cắt đi phần tử [2, 3]
của mảng arr
nên mảng arr
chỉ còn lại một phần tử [1]
Chèn (Inserting)
Ta sẽ dùng cách này để chèn một giá trị vào mảng
arr = [1,2,3]
arr.insert(1, [10, 20])
p arr # => [1, [10, 20], 2, 3]
Nó chèn mảng [10, 20]
thành giá trị thứ hai trong mảng arr
. Nếu bạn chỉ muốn chèn số, ta dùng thêm flatten!
arr.insert(1, [10, 20]).flatten! # => [1, 10, 20, 2, 3]
Hoặc dùng toán tử *
, cách này ngắn gọn hơn
arr = [1,2,3]
arr.insert(1, *[10, 20])
p arr # => [1, 10, 20, 2, 3]
Để thay thế một hoặc nhiều giá trị bởi giá trị từ mảng khác, ta dùng cách này
arr = [1,2,3]
arr[0..0] = [10, 20]
p arr # => [10, 20, 2, 3]
So sánh mảng
Để so sánh mảng, chúng ta sử dụng toán tử <=>
. So sánh sẽ trả về số nguyên (-1, 0, hoặc +1) nếu mảng đó nhỏ hơn, bằng, hoặc lớn hơn mảng còn lại.
Khi so sáng mảng, Ruby so sánh lần lượt từng phần tử, ví dụ
arr = [1,2,3]
another_arr = [1,2,4]
arr <=> another_arr # => -1
Ruby so sánh: 1 ở arr
với 1 ở another_arr
, sau đó là 2 với 2, và 3 nhỏ hơn 4, vì vậy trả về giá trị -1
có nghĩa arr < another_arr
.
Nếu tất cả các phần tử đều giống nhau sẽ trả về 0
arr = [1, 2, 3]
another_arr = [1, 2, 3]
arr <=> another_arr # => 0
Nếu bất kì phần tử nào trong mảng đầu tiền lớn hơn phần tử tương ứng trong mảng còn lại, nó sẽ trả về 1
arr = [1, 5, 3]
another_arr = [1, 2, 3]
arr <=> another_arr # => 1 (5 lớn hơn 2)
Còn nếu phần tử trong mảng không so sánh được? Hãy xem
arr = [1, 5, 3]
another_arr = [1, "test", 3]
arr <=> another_arr # => nil
Nếu Ruby không thể so sánh 2 phần tử, nó sẽ trả về nil
Còn nếu kích thước 2 mảng khác nhau?
arr = [1, 2, 3]
another_arr = [1, 2, 3, 4]
p arr <=> another_arr # => -1
Nếu độ dài của mảng đầu tiên nhỏ hơn độ dài của mảng còn lại, nó sẽ trả về -1
, ngược lại sẽ trả về 1
arr = [1, 2, 3, 4, 5]
another_arr = [1, 2]
arr <=> another_arr # => 1
Bài viết khá đơn giản nhưng mong rằng hữu ích với bạn. Cảm ơn đã theo dõi!
All rights reserved