Як розділити послідовність на дві частини за присудком?


120

Як розділити послідовність на два списки присудком?

Альтернатива: я можу використовувати filterта filterNotабо написати власний метод, але чи немає кращого загальнішого (вбудованого) методу?

Відповіді:


193

За допомогою partitionметоду:

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)є способом зруйнувати отриманий кордон з partitionчитабельним способом.
k0pernikus

2
Можна скоротити функцію всередині розділу _ % 2 == 0.
k0pernikus

138

Добре , що partitionбуло то , що ви хотіли - є ще один метод , який також використовує предикат розділити список на дві частини : span.

У першому розділі будуть розміщені всі "справжні" елементи в одному списку, а інші - у другому.

span буде розміщувати всі елементи в одному списку, поки елемент не стане "false" (з точки зору присудка). З цього моменту він додасть елементи до другого списку.

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

2
Саме те, що я шукав. Коли список упорядковується відповідним критерієм, це має набагато більше сенсу.
erich2k8

16

Ви можете поглянути на scalex.org - це дозволяє шукати стандартну бібліотеку Scala для функцій за їх підписом. Наприклад, введіть таке:

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

Ви побачили б розділ .


10
Домен scalex.org наразі мертвий. Але є альтернатива - scala-search.org ;-).
пн

1
Навчимо ловити рибу!
ЦЕ ПОТРІБНИК ПОТРІБНО ДОПОМОГА

1
@monnef Якась альтернатива для вашої альтернативи на 2020 рік? :)
tehCivilian

14

Ви також можете використовувати foldLeft, якщо вам потрібно щось трохи додатково. Я щойно написав такий код, коли розділ не вирізав його:

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
Дуже приємний спосіб використовувати кортеж і складкуLeft. Я в кінцевому підсумку скористався ListBuffer для ефективного збереження двох списків в одному порядку, але в іншому випадку це було місце для того, що мені потрібно.
Метт Хагопян

1

Я знаю, що я можу запізнитися на вечірку, і є більш конкретні відповіді, але ви могли б добре скористатися 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)

Це робить ваш код трохи більш надійним у майбутньому, якщо вам потрібно змінити умову на щось, що не є булевим.


0

Якщо ви хочете розділити список на більш ніж 2 частини та проігнорувати межі, ви можете використовувати щось подібне (змінити, якщо вам потрібно шукати вставки)

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"})
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.