Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

7 Ví dụ Code Ruby Bắt Buộc Phải Xem cho Developers

Một cách để học các thủ thuật, pattern và phương thức Ruby mới là đọc code người khác đã viết.

Nhưng bạn tìm code thú vị đáng đọc ở đâu?

Chúng ta có nhiều dự án mã nguồn mở, và các trang thách thức coding cho phép bạn xem giải pháp từ developers khác sau khi bạn nộp bài làm của mình.

Trong bài viết này:

Tôi biên soạn 7 ví dụ mà tôi nghĩ bạn sẽ thích.

Tôi cũng sẽ đưa ra một số nhận xét về từng ví dụ để giúp bạn tận dụng tối đa.

Tổng của hai số (Sum Of Two Numbers)

Trong ví dụ này, chúng ta muốn biết: cho một mảng các số duy nhất, có tổ hợp của hai số nào cộng lại bằng số mục tiêu không.

Code:

def sum_eq_n?(arr, n)
  return true if arr.empty? && n == 0
  arr.product(arr).reject { |a,b| a == b }.any? { |a,b| a + b == n }
end

Điều này thú vị vì tôi đang dùng phương thức product ở đây.

Khi bạn dùng phương thức này, giống như có một vòng lặp bên trong vòng lặp kết hợp tất cả giá trị trong mảng A với tất cả giá trị trong mảng B.

Đếm, Map & Tìm (Counting, Mapping & Finding)

Giả sử bạn muốn tìm số bị thiếu trong một dãy số học, như (2,4,6,10).

Chúng ta có thể dùng chiến lược tính sự khác biệt giữa các số.

[2, 2, 4]

Mục tiêu ở đây là tìm ra dãy số là gì.

Nó đang tăng hay giảm?

Bao nhiêu?

Code này tiết lộ dãy số:

differences = [2, 2, 4]
differences.max_by { |n| differences.count(n) } # 2
# Đây là khoảng tăng giữa các số trong dãy

Khi đã biết dãy số, chúng ta có thể so sánh tất cả các số để tìm số bị thiếu.

Code ở đây:

def find_missing(sequence)
  consecutive = sequence.each_cons(2)
  differences = consecutive.map { |a,b| b - a }
  sequence = differences.max_by { |n| differences.count(n) }
  missing_between = consecutive.find { |a,b| (b - a) != sequence }
  missing_between.first + sequence
end
find_missing([2,4,6,10]) # 8

Đếm xem chúng ta dùng bao nhiêu phương thức Ruby ở đây để làm việc nặng nhọc cho chúng ta 🙂

Ví dụ Regular Expression

Nếu bạn làm việc với chuỗi và muốn tìm pattern, regular expressions là người bạn.

Chúng có thể hơi khó để làm đúng, nhưng thực hành tạo nên sự thành thạo!

Bây giờ:

Giả sử chúng ta muốn biết xem một chuỗi cho trước có tuân theo pattern NGUYÊN ÂM đến KHÔNG NGUYÊN ÂM không.

Như thế này:

"ateciyu"

Khi đó chúng ta có thể dùng regular expression, kết hợp với phương thức match? để giải quyết.

Ví dụ code:

def alternating_characters?(s)
  type = [/[aeiou]/, /[^aeiou]/].cycle
  if s.start_with?(/[^aeiou]/)
    type.next
  end
  s.chars.all? { |ch| ch.match?(type.next) }
end
alternating_characters?("ateciyu") # true

Chú ý một vài điều:

  1. Chúng ta dùng phương thức cycle để tiếp tục chuyển đổi giữa regex NGUYÊN ÂM và KHÔNG NGUYÊN ÂM.
  2. Chúng ta chuyển chuỗi thành mảng ký tự với chars để có thể dùng phương thức all?.

Ví dụ Đệ quy & Stack (Recursion & Stack Example)

Đệ quy là khi một phương thức gọi chính nó nhiều lần như một cách để tiến tới giải pháp.

Nhiều bài toán thú vị có thể giải quyết bằng đệ quy.

Nhưng vì đệ quy có giới hạn, bạn có thể dùng cấu trúc dữ liệu stack thay thế.

Bây giờ:

Hãy xem ví dụ nơi chúng ta muốn tìm "Power Set" của một mảng cho trước. Power Set là tập hợp của tất cả các subset có thể tạo từ mảng.

Ví dụ với đệ quy:

def get_numbers(list, index = 0, taken = [])
  return [taken] if index == list.size
  get_numbers(list, index+1, taken) + get_numbers(list, index+1, taken + [list[index]])
end
get_numbers([1,2,3])

Cùng bài toán giải quyết bằng stack:

def get_numbers_stack(list)
  stack = [[0, []]]
  output = []
  until stack.empty?
    index, taken = stack.pop
    next output << taken if index == list.size
    stack.unshift [index + 1, taken]
    stack.unshift [index + 1, taken + [list[index]]]
  end
  output
end

Ý tưởng ở đây là mỗi lần lặp của thuật toán, chúng ta hoặc là lấy một số, hoặc không lấy số đó.

Chúng ta nhánh ra và thử cả hai kết quả để tạo ra tất cả tổ hợp có thể.

Hãy tưởng tượng một cây mà mỗi lá là một giải pháp.

Một vài điều để chú ý:

  1. Giải pháp đệ quy ngắn gọn hơn
  2. Phần "tiến triển" thực sự của thuật toán (index + 1) gần như giống nhau
  3. Stack chúng ta dùng chỉ là một mảng vì Ruby không có class Stack

Ví dụ Method Chaining (Method Chaining Example)

Đây là ví dụ yêu thích của tôi vì nó cho thấy Ruby mạnh mẽ như thế nào.

Kết hợp các phương thức cho phép bạn lấy đầu ra từ một phương thức và truyền vào phương thức khác.

Giống như dây chuyền sản xuất!

Bạn bắt đầu với một số nguyên liệu thô (input), sau đó qua quá trình gọi các phương thức, bạn dần biến nguyên liệu thô thành kết quả mong muốn.

Ví dụ:

def longest_repetition(string)
  max = string
    .chars
    .chunk(&:itself)
    .map(&:last)
    .max_by(&:size)
  max ? [max[0], max.size] : ["", 0]
end
longest_repetition("aaabb") # ["a", 3]

Cho một chuỗi, code này sẽ tìm ký tự lặp lại dài nhất.

Lưu ý:

  • Cách format code này để tối đa hóa tính đọc được
  • Sử dụng pattern Symbol#to_proc (&:size)

Btw, đừng nhầm lẫn với "Luật Demeter" (Law of Demeter).

Luật đó nói về việc móc nối vào nội bộ của đối tượng khác.

Ở đây chúng ta chỉ biến đổi đối tượng.

Ví dụ With Index (With Index Example)

Bạn có muốn có chỉ số hiện tại khi lặp qua tập hợp các item?

Bạn có thể dùng phương thức with_index.

Ví dụ:

def reverse_alternate(string)
  string.gsub(/[^\s]+/).with_index { |w, idx| idx.even? ? w : w.reverse }
end
reverse_alternate("Apples Are Good") # "Apples erA Good"

Chú ý:

  • Chúng ta kết hợp with_index và even? để tìm xem có phải đảo ngược từ hiện tại không
  • Gsub không có block trả về đối tượng Enumerator, cho phép bạn chain nó với các phương thức khác

Ví dụ Each With Object (Each With Object Example)

Một phương thức thú vị khác là each_with_object, và bạn thân của nó with_object.

Bạn có thể dùng hai phương thức này khi cần một đối tượng để chứa kết quả.

Ví dụ:

def clean_string(str)
  str
    .chars
    .each_with_object([]) { |ch, obj| ch == "#" ? obj.pop : obj << ch }
    .join
end
clean_string("aaa#b")

Trong ví dụ này, chúng ta muốn xóa ký tự cuối khi tìm thấy ký hiệu #.

Chú ý:

  • each_with_object nhận một đối số, là đối tượng chúng ta muốn bắt đầu. Đối số này trở thành tham số block thứ 2.
  • Chúng ta chuyển chuỗi thành mảng ký tự (chars) và rồi chuyển lại chuỗi khi xong (join).
  • Chúng ta dùng toán tử ternary để quyết định làm gì, điều này làm code ngắn gọn hơn.

Tóm tắt

Trong bài viết này, bạn đã thấy một số ví dụ code thú vị với nhận xét và giải thích của tôi để giúp bạn viết code Ruby tốt hơn.

Đừng quên chia sẻ bài viết này để nhiều người hơn có thể thưởng thức.

Cảm ơn bạn đã đọc!