withFilter thay vì filter


Câu trả lời:


121

Từ tài liệu Scala :

Lưu ý: sự khác biệt giữa c filter pc 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 theo map, 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.


Hy vọng một ngày nào đó họ vẫn thêm những phương pháp này.
Kigyo

1
@Kigyo Tôi không nghĩ rằng bạn phải tự mình sử dụng withFilter (ngoại trừ ẩn trong các biểu thức). Sử dụng viewnếu bạn muốn bản đồ / bộ lọc lười biếng.
Luigi Plinge

Tôi hiểu rồi. Sự khác biệt chính xác giữa viewwithFilter? Tại sao chế độ xem không được sử dụng for-loops?
Kigyo

5
Chỉ để tham khảo, tôi nghĩ rằng Bộ sưu tập - Mẹo và Thủ thuật cung cấp thông tin nổi bật. H5 không được cố định, nhưng bạn có thể tìm kiếm Don’t create temporary collectionstrong phần được liên kết.
sthzg

4
Về việc sử dụng rõ ràng 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.
Chuck Daniels

9

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 filterwithFilter.

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


1

Lý do chính bởi vì forall / being không được triển khai là trường hợp sử dụng là:

  • bạn có thể áp dụng một cách lười biếng vớiFilter vào một luồng vô hạn / có thể lặp lại
  • bạn có thể lười biếng áp dụng một vớiFilter khác (và lặp đi lặp lại)

Để 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)


1

Đối với phần forall / tồn tại:

someList.filter(conditionA).forall(conditionB)

sẽ giống như (mặc dù hơi thiếu trực quan)

!someList.exists(conditionA && !conditionB)

Tương tự như vậy, .filter (). Tồn tại () có thể được kết hợp thành một kiểm tra tồn tại ()?


-3

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)

-5

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 mapflatMap.

Hơn nữa, tối ưu hóa này vô dụng trên các bộ sưu tập nhỏ…

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.