2 Aug 2016

Scala: Một vài điểm lưu ý khi làm việc với List

a. Scala tồn tại 2 khái niệm cùng được biểu diễn bằng ::, một là method của companion class List, 2 là constructor của class scala.::.
Khi làm việc với List chúng ta có "cons" pattern hay còn có tên là prepend method. 

Method này được biểu diễn như sau:
def ::[B >: A] (x: B): List[B] =
  new scala.collection.immutable.::(x, this)
Trong đó x là phần tử được gắn vào đầu của List sau khi method này được gọi (thay vì nối vào cuối).
Do vậy nếu gọi
 1::List(2, 3)

Thì ta có kết quả là List[Int] = List(1, 2, 3) thay vì List[Int] = List(2, 3, 1) khi gọi method append (:::)
Một chú ý quan trọng trong scala, khi gặp các method bắt đầu từ dấu ":", thì method này được apply từ phải qua trái, thay vì từ trái qua phải. Với ví dụ trên, có thể viết lại thành List(2,3).::(1)

Nhưng khi làm việc với pattern matching trên List, chúng ta thường triển khai như sau:
//reverse một List

def rev[T](xs: List[T]): List[T] = xs match {
  case List() => xs
  case x :: xs1 => rev(xs1) ::: List(x)
}
Để ý khi chúng ta dùng case x::xs1, chúng ta đang không sử dụng method prepend của List, mà đang sử dụng một constructor. 
Khi sử dụng pattern matching trên List, chúng ta đang sử dụng scala.:: constructor, không phải sử dụng method prepend của List. Do vậy khi gọi x::xs1, ta  đã tạo ra một instance của class scala.::, để dễ hiểu ta có thế viết lại bàm reverse List như sau:
//reverse một List

def rev[T](xs: List[T]): List[T] = xs match {
  case List() => xs
  case scala.::(_, _) => rev(xs.tail) ::: List(xs.head)
}
b. Lấy chiều dài của List là một thao tác tốn nhiều resource, ta phải duyệt qua hết các phần tử của List cho đến phần tử cuối cùng để lấy chiều dài, do vậy nếu không có nhu cầu đặc biệt cần lấy chiều dài của List, để kiểm tra List có rỗng hay không, thay vì kiểm l.length == 0, nên dùng l.isEmpty.

c. Cũng vì lí do trên, nên trong hầu hết trường hợp, để thêm một phần tử mới vào List, ta nên dùng method prepend (::), thay vì append(::). Và cố gắng sắp xếp dữ liệu để các phần tử thường xuyên được dùng nằm ở đầu của List thay vì ở cuối.

No comments:

Disqus