Bir dizi yüklemeye göre nasıl iki parçaya bölünür?


120

Bir diziyi bir yüklemeye göre iki listeye nasıl bölerim?

Alternatif: Kullanabilir filterve filterNotveya kendi yöntemimi yazabilirim, ancak daha genel (yerleşik) bir yöntem yok mu?

Yanıtlar:


194

partitionYöntemi kullanarak :

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)sonuçtaki demeti partitionokunabilir bir şekilde yok etmenin bir yoludur.
k0pernikus

2
Bir bölüm içindeki işlevi kısaltabilir _ % 2 == 0.
k0pernikus

138

İyi partitionİstediğin şeydi - ayrıca ikiye listesini bölmek için bir yüklemi kullanan başka bir yöntem var: span.

İlki, bölüm tüm "true" öğeleri bir listeye ve diğerlerini ikinci listeye koyacaktır.

span , bir öğe "yanlış" olana kadar (yüklem açısından) tüm öğeleri tek bir listeye koyacaktır. Bu noktadan sonra, öğeleri ikinci listeye koyacaktır.

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

2
Tam olarak aradığım şey. Liste ilgili bir kritere göre sıralandığında bu çok daha mantıklıdır.
erich2k8

16

Scalex.org'a bir göz atmak isteyebilirsiniz - bu, scala standart kitaplığında işlevleri imzalarına göre aramanıza olanak tanır. Örneğin, şunu yazın:

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

Bölme göreceksiniz .


10
scalex.org alanı şu anda kapanmış. Ama alternatif var - scala-search.org ;-).
monnef

1
Balık tutmayı öğretmek!
BU KULLANICININ YARDIM İHTİYACI

1
@monnef 2020 alternatifiniz için bir alternatif var mı? :)
tehCivilian

14

Biraz fazladan bir şeye ihtiyacınız varsa foldLeft'i de kullanabilirsiniz. Bölüm kesmediğinde böyle bir kod yazdım:

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
Tuple ve foldLeft kullanmanın çok güzel yolu İki listeyi aynı sırada verimli bir şekilde tutmak için bir ListBuffer kullanmaya son verdim, ancak aksi halde ihtiyacım olan şey için yerinde idi.
Matt Hagopian

1

Partiye geç kalabileceğimi ve daha spesifik cevaplar olduğunu biliyorum, ancak şunu iyi bir şekilde kullanabilirsiniz: 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)

Bu, koşulu boole olmayan bir şeye dönüştürmeniz gerekiyorsa kodunuzu biraz daha geleceğe hazır hale getirir.


0

Bir listeyi 2'den fazla parçaya bölmek ve sınırları göz ardı etmek istiyorsanız, bunun gibi bir şey kullanabilirsiniz (ints'i aramanız gerekiyorsa değiştirin)

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"})
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.