<commit_before>---
layout: page
title: Các tập dữ liệu
category: basics
order: 2
lang: vi
---

List (Danh sách), tuple, keyword (danh sách từ khoá), map, dict (từ điển) và functional combinators (toán tử kết hợp hướng chức năng)

## Mục Lục

- [List (Danh sách)](#lists)
	- [Nối List](#list-concatenation)
	- [Phép trừ List](#list-subtraction)
	- [Phần tử Đầu / Đuôi](#head--tail)
- [Tuple](#tuples)
- [Keyword List (Danh sách từ khoá)](#keyword-lists)
- [Map](#maps)

## List (Danh sách)

List (danh sách) là một tập hợp các giá trị, có thể bao gồm nhiều kiểu dữ liệu; có thể bao gồm giá trị lặp:

```elixir
iex> [3.41, :pie, "Apple"]
[3.41, :pie, "Apple"]
```

Với Elixir, list được xây dựng từ linked list (danh sách liên kết). Điều này dẫn đến việc truy cập kích thước của list là một thao tác với độ phức tạp `O(n)`. Vì lý do này, chèn phần tử vào đầu list thường nhanh hơn so với thêm vào cuối list:

```elixir
iex> list = [3.41, :pie, "Apple"]
[3.41, :pie, "Apple"]
iex> ["π"] ++ list
["π", 3.41, :pie, "Apple"]
iex> list ++ ["Cherry"]
[3.41, :pie, "Apple", "Cherry"]
```

### Nối list

Dùng toán tử `++/2` để nối list:

```elixir
iex> [1, 2] ++ [3, 4, 1]
[1, 2, 3, 4, 1]
```

### Phép trừ list

Phép trừ list có thể thực hiện thông qua toán tử `--/2`; list trừ có thể bao gồm những giá trị không có trong list bị trừ:

```elixir
iex> ["foo", :bar, 42] -- [42, "bar"]
["foo", :bar]
```

### Phần tử Đầu / Đuôi

Khi sử dụng danh sách, ta thường phải dùng tới đầu và đuôi của danh sách. Đầu là phần tử đầu tiên của danh sách và đuôi là danh sách những phần tử còn lại. Elixir hỗ trợ hai hàm hữu dụng, `hd` và `tl`, để truy cập đầu và đuôi:

```elixir
iex> hd [3.41, :pie, "Apple"]
3.41
iex> tl [3.41, :pie, "Apple"]
[:pie, "Apple"]
```

Bên cạnh những hàm đã nói ở trên, bạn có thể dùng toán tử ống dẫn `|`; chúng ta sẽ còn gặp lại toán tử này trong các bài sau:

```elixir
iex> [h|t] = [3.41, :pie, "Apple"]
[3.41, :pie, "Apple"]
iex> h
3.41
iex> t
[:pie, "Apple"]
```

## Tuple

Tuple cũng tương tự như list nhưng luôn được lưu cạnh nhau trong bộ nhớ. Điều này dẫn tới việc truy cập kích thước tuple rất nhanh nhưng thay đổi thì chậm. Sau khi thay đổi, tuple mới phải được copy lại hết vào bộ nhớ:

```elixir
iex> {3.41, :pie, "Apple"}
{3.41, :pie, "Apple"}
```

Thông thường, tuple được sử dụng để trả về những thông tin thêm vào của các hàm; bạn sẽ thấy rõ hơn sự hữu dụng của tuple khi pattern matching (dùng so khớp mẫu):

```elixir
iex> File.read("path/to/existing/file")
{:ok, "... contents ..."}
iex> File.read("path/to/unknown/file")
{:error, :enoent}
```<commit_msg>Fixes based on feedbacks by @trenix<commit_after>---
layout: page
title: Các tập dữ liệu
category: basics
order: 2
lang: vi
---

List (Danh sách), tuple, keyword (danh sách từ khoá), map, dict (từ điển) và functional combinators (toán tử kết hợp hướng chức năng)

## Mục Lục

- [List (Danh sách)](#lists)
	- [Nối List](#list-concatenation)
	- [Phép trừ List](#list-subtraction)
	- [Phần tử Đầu / Đuôi](#head--tail)
- [Tuple](#tuples)
- [Keyword List (Danh sách từ khoá)](#keyword-lists)
- [Map](#maps)

## List (Danh sách)

List (danh sách) là một tập hợp các giá trị, có thể bao gồm nhiều kiểu dữ liệu; có thể bao gồm giá trị lặp:

```elixir
iex> [3.41, :pie, "Apple"]
[3.41, :pie, "Apple"]
```

Elixir triển khai list như những linked list (danh sách liên kết). Có nghĩa là việc truy cập độ dài của list là thao tác có độ phức tạp `O(n)`. Vì lý do này, chèn phần tử vào đầu list thường nhanh hơn so với thêm vào cuối list:

```elixir
iex> list = [3.41, :pie, "Apple"]
[3.41, :pie, "Apple"]
iex> ["π"] ++ list
["π", 3.41, :pie, "Apple"]
iex> list ++ ["Cherry"]
[3.41, :pie, "Apple", "Cherry"]
```

### Nối list

Dùng toán tử `++/2` để nối list:

```elixir
iex> [1, 2] ++ [3, 4, 1]
[1, 2, 3, 4, 1]
```

### Phép trừ list

Phép trừ list có thể thực hiện thông qua toán tử `--/2`; list trừ có thể bao gồm những giá trị không có trong list bị trừ:

```elixir
iex> ["foo", :bar, 42] -- [42, "bar"]
["foo", :bar]
```

### Phần tử Đầu / Đuôi

Khi sử dụng danh sách, ta thường phải dùng tới đầu và đuôi của danh sách. Đầu là phần tử đầu tiên của danh sách và đuôi là danh sách những phần tử còn lại. Elixir hỗ trợ hai hàm hữu dụng, `hd` và `tl`, để truy cập đầu và đuôi:

```elixir
iex> hd [3.41, :pie, "Apple"]
3.41
iex> tl [3.41, :pie, "Apple"]
[:pie, "Apple"]
```

Bên cạnh những hàm đã nói ở trên, bạn có thể dùng toán tử ống dẫn `|`; chúng ta sẽ còn gặp lại toán tử này trong các bài sau:

```elixir
iex> [h|t] = [3.41, :pie, "Apple"]
[3.41, :pie, "Apple"]
iex> h
3.41
iex> t
[:pie, "Apple"]
```

## Tuple

Tuple cũng tương tự như list nhưng được lưu trữ một cách liên tục trên bộ nhớ. Điều này dẫn tới việc truy cập kích thước tuple rất nhanh nhưng thay đổi thì chậm. Sau khi thay đổi, tuple mới phải được copy toàn bộ vào bộ nhớ:

```elixir
iex> {3.41, :pie, "Apple"}
{3.41, :pie, "Apple"}
```

Thông thường, tuple được sử dụng như một cơ chế để trả về các thông tin bổ sung từ các hàm; sự hữu dụng của nó trở nên rõ ràng hơn khi chúng ta đụng tới pattern matching (so khớp mẫu):

```elixir
iex> File.read("path/to/existing/file")
{:ok, "... contents ..."}
iex> File.read("path/to/unknown/file")
{:error, :enoent}
```
{'fraction_non_alphanumeric': 0.15887670705904983, 'fraction_numerical': 0.022696672437007116, 'mean_word_length': 3.5855379188712524, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6417169', 'n_tokens_mistral': 2987, 'n_tokens_neox': 2961, 'n_words': 895}