Elixir - Enumerables

Enumerable là một đối tượng có thể được liệt kê. "Enumerated" có nghĩa là đếm từng thành viên của một tập hợp / tập hợp / danh mục (thường theo thứ tự, thường là theo tên).

Elixir cung cấp khái niệm về liệt kê và mô-đun Enum để làm việc với chúng. Các chức năng trong mô-đun Enum được giới hạn, như tên đã nói, liệt kê các giá trị trong cấu trúc dữ liệu. Ví dụ về cấu trúc dữ liệu có thể liệt kê là danh sách, tuple, bản đồ, v.v. Mô-đun Enum cung cấp cho chúng ta hơn 100 hàm để xử lý các enum. Chúng ta sẽ thảo luận một vài chức năng quan trọng trong chương này.

Tất cả các hàm này nhận một enumerable làm phần tử đầu tiên và một hàm làm phần tử thứ hai và hoạt động trên chúng. Các chức năng được mô tả dưới đây.

tất cả?

Khi chúng tôi sử dụng all? chức năng, toàn bộ tập hợp phải đánh giá là true nếu không sẽ trả về false. Ví dụ: để kiểm tra xem tất cả các phần tử trong danh sách có phải là số lẻ hay không.

res = Enum.all?([1, 2, 3, 4], fn(s) -> rem(s,2) == 1 end) 
IO.puts(res)

Khi chương trình trên được chạy, nó tạo ra kết quả sau:

false

Điều này là do không phải tất cả các phần tử của danh sách này đều kỳ lạ.

bất kì?

Như tên cho thấy, hàm này trả về true nếu bất kỳ phần tử nào của tập hợp đánh giá là true. Ví dụ -

res = Enum.any?([1, 2, 3, 4], fn(s) -> rem(s,2) == 1 end)
IO.puts(res)

Khi chương trình trên được chạy, nó tạo ra kết quả sau:

true

khúc gỗ

Hàm này chia bộ sưu tập của chúng ta thành các phần nhỏ có kích thước được cung cấp như đối số thứ hai. Ví dụ -

res = Enum.chunk([1, 2, 3, 4, 5, 6], 2)
IO.puts(res)

Khi chương trình trên được chạy, nó tạo ra kết quả sau:

[[1, 2], [3, 4], [5, 6]]

mỗi

Có thể cần phải lặp lại một bộ sưu tập mà không tạo ra giá trị mới, đối với trường hợp này, chúng tôi sử dụng each chức năng -

Enum.each(["Hello", "Every", "one"], fn(s) -> IO.puts(s) end)

Khi chương trình trên được chạy, nó tạo ra kết quả sau:

Hello
Every
one

bản đồ

Để áp dụng chức năng của chúng tôi cho từng mục và tạo ra một bộ sưu tập mới, chúng tôi sử dụng chức năng bản đồ. Nó là một trong những cấu trúc hữu ích nhất trong lập trình hàm vì nó khá diễn đạt và ngắn gọn. Chúng ta hãy xem xét một ví dụ để hiểu điều này. Chúng tôi sẽ nhân đôi các giá trị được lưu trữ trong danh sách và lưu trữ trong danh sách mớires -

res = Enum.map([2, 5, 3, 6], fn(a) -> a*2 end)
IO.puts(res)

Khi chương trình trên được chạy, nó tạo ra kết quả sau:

[4, 10, 6, 12]

giảm

Các reducehàm giúp chúng ta giảm số lượng của chúng ta xuống một giá trị duy nhất. Để làm điều này, chúng tôi cung cấp một bộ tích lũy tùy chọn (5 trong ví dụ này) để được chuyển vào hàm của chúng tôi; nếu không có bộ tích lũy nào được cung cấp, giá trị đầu tiên được sử dụng -

res = Enum.reduce([1, 2, 3, 4], 5, fn(x, accum) -> x + accum end)
IO.puts(res)

Khi chương trình trên được chạy, nó tạo ra kết quả sau:

15

Bộ tích lũy là giá trị ban đầu được chuyển đến fn. Từ cuộc gọi thứ hai trở đi, giá trị trả về từ cuộc gọi trước được chuyển dưới dạng tích lũy. Chúng tôi cũng có thể sử dụng giảm mà không cần tích lũy -

res = Enum.reduce([1, 2, 3, 4], fn(x, accum) -> x + accum end)
IO.puts(res)

Khi chương trình trên được chạy, nó tạo ra kết quả sau:

10

uniq

Hàm uniq loại bỏ các bản sao khỏi bộ sưu tập của chúng tôi và chỉ trả về tập hợp các phần tử trong bộ sưu tập. Ví dụ -

res = Enum.uniq([1, 2, 2, 3, 3, 3, 4, 4, 4, 4])
IO.puts(res)

Khi chạy chương trình trên, nó tạo ra kết quả sau:

[1, 2, 3, 4]

Đánh giá háo hức

Tất cả các chức năng trong mô-đun Enum đều háo hức. Nhiều hàm mong đợi có thể liệt kê và trả về một danh sách. Điều này có nghĩa là khi thực hiện nhiều thao tác với Enum, mỗi thao tác sẽ tạo ra một danh sách trung gian cho đến khi chúng ta đạt được kết quả. Chúng ta hãy xem xét ví dụ sau để hiểu điều này -

odd? = &(odd? = &(rem(&1, 2) != 0) 
res = 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum 
IO.puts(res)

Khi chương trình trên được chạy, nó tạo ra kết quả sau:

7500000000

Ví dụ trên có một đường dẫn hoạt động. Chúng tôi bắt đầu với một phạm vi và sau đó nhân từng phần tử trong phạm vi với 3. Thao tác đầu tiên này bây giờ sẽ tạo và trả về một danh sách với 100_000 mục. Sau đó, chúng tôi giữ tất cả các phần tử lẻ khỏi danh sách, tạo một danh sách mới, bây giờ với 50_000 mục, và sau đó chúng tôi tổng hợp tất cả các mục.

Các |> biểu tượng được sử dụng trong đoạn mã trên là pipe operator: nó chỉ đơn giản lấy đầu ra từ biểu thức ở phía bên trái của nó và chuyển nó làm đối số đầu tiên cho lời gọi hàm ở phía bên phải của nó. Nó tương tự như Unix | nhà điều hành. Mục đích của nó là làm nổi bật luồng dữ liệu được chuyển đổi bởi một loạt các chức năng.

Không có pipe toán tử, mã trông phức tạp -

Enum.sum(Enum.filter(Enum.map(1..100_000, &(&1 * 3)), odd?))

Chúng tôi có nhiều chức năng khác, tuy nhiên, chỉ có một số chức năng quan trọng được mô tả ở đây.