Làm thế nào để chia một dãy thành hai phần bằng vị ngữ?


120

Làm cách nào để chia một chuỗi thành hai danh sách bằng một vị từ?

Thay thế: Tôi có thể sử dụng filterfilterNothoặc viết phương thức của riêng mình, nhưng không có phương thức nào tốt hơn (tích hợp sẵn) tốt hơn?

Câu trả lời:


193

Bằng cách sử dụng partitionphương pháp:

scala> List(1,2,3,4).partition(x => x % 2 == 0)
res0: (List[Int], List[Int]) = (List(2, 4),List(1, 3))

1
val (even, odd) = List(1,2,3,4).partition(x => x % 2 == 0)là một cách để hủy bộ dữ liệu kết quả partitiontheo cách có thể đọc được.
k0pernikus

2
Người ta có thể rút ngắn chức năng bên trong phân vùng thành _ % 2 == 0.
k0pernikus

138

Tốt đó partitionlà điều bạn muốn - có một phương pháp mà còn sử dụng một vị để chia một danh sách trong hai: span.

Phân vùng đầu tiên sẽ đặt tất cả các phần tử "true" trong một danh sách và các phần tử khác trong danh sách thứ hai.

span sẽ đặt tất cả các phần tử trong một danh sách cho đến khi một phần tử là "false" (về mặt vị từ). Từ thời điểm đó trở đi, nó sẽ đưa các phần tử vào danh sách thứ hai.

scala> Seq(1,2,3,4).span(x => x % 2 == 0)
res0: (Seq[Int], Seq[Int]) = (List(),List(1, 2, 3, 4))

2
Chính xác những gì tôi đang tìm kiếm. Khi danh sách được sắp xếp theo một tiêu chí liên quan, điều này có ý nghĩa hơn rất nhiều.
erich2k8

16

Bạn có thể muốn xem scalex.org - nó cho phép bạn tìm kiếm thư viện tiêu chuẩn của scala cho các hàm bằng chữ ký của chúng. Ví dụ: nhập như sau:

List[A] => (A => Boolean) => (List[A], List[A])

Bạn sẽ thấy phân vùng .


10
miền scalex.org hiện đã chết. Nhưng có một lựa chọn thay thế - scala-search.org ;-).
monnef

1
Dạy cách bắt một con cá!
NGƯỜI DÙNG NÀY CẦN GIÚP ĐỠ

1
@monnef Có bất kỳ giải pháp thay thế nào cho thay thế của bạn cho năm 2020 không? :)
tehCivilian

14

Bạn cũng có thể sử dụng foldLeft nếu cần thêm một chút gì đó. Tôi chỉ viết một số mã như thế này khi phân vùng không cắt nó:

val list:List[Person] = /* get your list */
val (students,teachers) = 
  list.foldLeft(List.empty[Student],List.empty[Teacher]) {
    case ((acc1, acc2), p) => p match {
      case s:Student => (s :: acc1, acc2)
      case t:Teacher  => (acc1, t :: acc2)
    }
  }

1
Một cách rất hay để sử dụng tuple và foldLeft. Tôi đã kết thúc bằng cách sử dụng ListBuffer để giữ hai danh sách theo thứ tự giống nhau một cách hiệu quả nhưng nếu không thì nó sẽ được đặt đúng chỗ cho những gì tôi cần.
Matt Hagopian

1

Tôi biết tôi có thể đến muộn bữa tiệc và có nhiều câu trả lời cụ thể hơn, nhưng bạn có thể tận dụng groupBy

val ret = List(1,2,3,4).groupBy(x => x % 2 == 0)

ret: scala.collection.immutable.Map[Boolean,List[Int]] = Map(false -> List(1, 3), true -> List(2, 4))

ret(true)
res3: List[Int] = List(2, 4)

ret(false)
res4: List[Int] = List(1, 3)

Điều này làm cho mã của bạn dễ kiểm chứng hơn trong tương lai nếu bạn cần thay đổi điều kiện thành một thứ gì đó không boolean.


0

Nếu bạn muốn chia danh sách thành nhiều hơn 2 phần và bỏ qua các giới hạn, bạn có thể sử dụng một cái gì đó như thế này (sửa đổi nếu bạn cần tìm kiếm các int)

def split(list_in: List[String], search: String): List[List[String]] = {
  def split_helper(accum: List[List[String]], list_in2: List[String], search: String): List[List[String]] = {
    val (h1, h2) = list_in2.span({x: String => x!= search})
    val new_accum = accum :+ h1
    if (h2.contains(search)) {
      return split_helper(new_accum, h2.drop(1), search) 
    }
    else {
    return accum
    }
  }
  return split_helper(List(), list_in, search)
}

// TEST

// split(List("a", "b", "c", "d", "c", "a"), {x: String => x != "x"})
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.