Việc sử dụng withFilter thay vì filter có luôn hiệu quả hơn khi sau đó áp dụng các chức năng như bản đồ, bản đồ phẳng, v.v. không?
Tại sao chỉ hỗ trợ map, flatmap và foreach? (Các chức năng mong đợi như forall / cũng tồn tại)
Việc sử dụng withFilter thay vì filter có luôn hiệu quả hơn khi sau đó áp dụng các chức năng như bản đồ, bản đồ phẳng, v.v. không?
Tại sao chỉ hỗ trợ map, flatmap và foreach? (Các chức năng mong đợi như forall / cũng tồn tại)
Câu trả lời:
Từ tài liệu Scala :
Lưu ý: sự khác biệt giữa
c filter pvàc withFilter plà cựu tạo ra một bộ sưu tập mới, trong khi sau này chỉ hạn chế lĩnh vực tiếp theomap,flatMap,foreach, vàwithFiltercác hoạt động.
Vì vậy, filtersẽ lấy bộ sưu tập ban đầu và tạo ra một bộ sưu tập mới, nhưng withFiltersẽ không nghiêm ngặt (tức là lười biếng) chuyển các giá trị chưa được lọc qua các cuộc gọi / map/ sau đó , lưu một lần thứ hai qua bộ sưu tập (đã lọc). Do đó, nó sẽ hiệu quả hơn khi chuyển qua các cuộc gọi phương thức tiếp theo này.flatMapwithFilter
Trên thực tế, withFilternó được thiết kế đặc biệt để làm việc với chuỗi các phương pháp này, đó là những gì mà một để hiểu được loại bỏ thành. Không có phương thức nào khác (chẳng hạn như forall/ exists) được yêu cầu cho việc này, vì vậy chúng đã không được thêm vào FilterMonadickiểu trả về withFilter.
viewnếu bạn muốn bản đồ / bộ lọc lười biếng.
viewvà withFilter? Tại sao chế độ xem không được sử dụng for-loops?
Don’t create temporary collectionstrong phần được liên kết.
withFilter, bản thân Martin Odersky cũng sử dụng nó một cách rõ ràng trong các khóa học Scala của anh ấy trên Coursera, điều mà tôi thực sự khuyên bạn nên sử dụng. Cho rằng anh ta làm như vậy, điều đó có thể mang lại cho người khác cảm giác thoải mái khi làm như vậy, mặc dù sự khác biệt thường chỉ là 1 ký tự. Ví dụ seq.view filter pvs seq withFilter p.
Ngoài câu trả lời xuất sắc của Shadowlands , tôi muốn đưa ra một ví dụ trực quan về sự khác biệt giữa filtervà withFilter.
Hãy xem xét đoạn mã sau
val list = List(1, 2, 3)
var go = true
val result = for(i <- list; if(go)) yield {
go = false
i
}
Hầu hết mọi người mong đợi resultđược bằng List(1). Đây là trường hợp kể từ Scala 2.8, vì tính dễ hiểu được dịch sang
val result = list withFilter {
case i => go
} map {
case i => {
go = false
i
}
}
Như bạn có thể thấy, bản dịch chuyển đổi điều kiện thành lời gọi tới withFilter. Trước Scala 2.8, tính dễ hiểu đã được dịch thành những thứ như sau:
val r2 = list filter {
case i => go
} map {
case i => {
go = false
i
}
}
Sử dụng filter, giá trị của resultsẽ là khá khác nhau: List(1, 2, 3). Thực tế là chúng tôi đang tạo gocờ falsekhông ảnh hưởng đến bộ lọc, vì bộ lọc đã được thực hiện. Một lần nữa, trong Scala 2.8, vấn đề này được giải quyết bằng cách sử dụng withFilter. Khi withFilterđược sử dụng, điều kiện được đánh giá mỗi khi một phần tử được truy cập bên trong một mapphương thức.
Tham khảo : - p.120, Scala in action (bao gồm Scala 2.10), Manning Publications, Milanjan Raychaudhuri - Suy nghĩ của Odersky về bản dịch dễ hiểu
Lý do chính bởi vì forall / being không được triển khai là trường hợp sử dụng là:
Để triển khai forall / being, chúng ta cần lấy tất cả các phần tử, loại bỏ sự lười biếng.
Ví dụ:
import scala.collection.AbstractIterator
class RandomIntIterator extends AbstractIterator[Int] {
val rand = new java.util.Random
def next: Int = rand.nextInt()
def hasNext: Boolean = true
}
//rand_integers is an infinite random integers iterator
val rand_integers = new RandomIntIterator
val rand_naturals =
rand_integers.withFilter(_ > 0)
val rand_even_naturals =
rand_naturals.withFilter(_ % 2 == 0)
println(rand_even_naturals.map(identity).take(10).toList)
//calling a second time we get
//another ten-tuple of random even naturals
println(rand_even_naturals.map(identity).take(10).toList)
Lưu ý rằng ten_rand_even_naturals vẫn là một trình lặp. Chỉ khi chúng tôi gọi toList , các số ngẫu nhiên sẽ được tạo và lọc theo chuỗi
Lưu ý rằng bản đồ (danh tính) tương đương với bản đồ (i => i) và nó được sử dụng ở đây để chuyển đổi đối tượng withFilter trở lại kiểu ban đầu (ví dụ: một bộ sưu tập, một luồng, một trình lặp)
Sử dụng để tạo ra lợi nhuận có thể là một công việc xung quanh, ví dụ:
for {
e <- col;
if e isNotEmpty
} yield e.get(0)
Như một giải pháp thay thế, bạn có thể triển khai các chức năng khác chỉ với mapvà flatMap.
Hơn nữa, tối ưu hóa này vô dụng trên các bộ sưu tập nhỏ…