[list] 고정 된 수의 요소를 사용하여 목록을 여러 목록으로 분할

최대 N 개의 항목이있는 목록으로 요소 목록을 분할하는 방법은 무엇입니까?

예 : 7 개의 요소가있는 목록이 주어지면 4 개의 그룹을 만들고 마지막 그룹은 더 적은 요소로 남겨 둡니다.

split(List(1,2,3,4,5,6,"seven"),4)

=> List(List(1,2,3,4), List(5,6,"seven"))



답변

나는 당신이 찾고 있다고 생각합니다 grouped. 반복자를 반환하지만 결과를 목록으로 변환 할 수 있습니다.

scala> List(1,2,3,4,5,6,"seven").grouped(4).toList
res0: List[List[Any]] = List(List(1, 2, 3, 4), List(5, 6, seven))


답변

슬라이딩 방식을 사용하여 작업을 수행하는 훨씬 더 쉬운 방법이 있습니다. 다음과 같이 작동합니다.

val numbers = List(1, 2, 3, 4, 5, 6 ,7)

목록을 크기 3의 작은 목록으로 나누고 싶다고 가정 해 보겠습니다.

numbers.sliding(3, 3).toList

너에게 줄 것이다

List(List(1, 2, 3), List(4, 5, 6), List(7))


답변

또는 직접 만들고 싶다면 :

def split[A](xs: List[A], n: Int): List[List[A]] = {
  if (xs.size <= n) xs :: Nil
  else (xs take n) :: split(xs drop n, n)
}

사용하다:

scala> split(List(1,2,3,4,5,6,"seven"), 4)
res15: List[List[Any]] = List(List(1, 2, 3, 4), List(5, 6, seven))

편집 : 2 년 후이 구현을 검토 sizeO (n)이므로이 구현을 권장하지 않습니다. 따라서이 메서드는 O (n ^ 2)이므로 내장 메서드가 큰 목록에서 더 빨라지는 이유를 설명합니다. 아래 설명에 언급되어 있습니다. 다음과 같이 효율적으로 구현할 수 있습니다.

def split[A](xs: List[A], n: Int): List[List[A]] =
  if (xs.isEmpty) Nil
  else (xs take n) :: split(xs drop n, n)

또는 (약간) 더 효율적으로 사용 splitAt:

def split[A](xs: List[A], n: Int): List[List[A]] =
  if (xs.isEmpty) Nil
  else {
    val (ys, zs) = xs.splitAt(n)
    ys :: split(zs, n)
  }


답변

꼬리 재귀 대 재귀에 대한 논의가 있었기 때문에 분할 방법의 꼬리 재귀 버전을 추가하고 있습니다. 나는 tailrec 주석을 사용하여 구현이 실제로 꼬리 반응이없는 경우 컴파일러가 불평하도록 강제했습니다. 꼬리 재귀는 내부적으로 루프로 바뀌고 스택이 무한정 커지지 않으므로 큰 목록에서도 문제를 일으키지 않을 것이라고 생각합니다.

import scala.annotation.tailrec


object ListSplitter {

  def split[A](xs: List[A], n: Int): List[List[A]] = {
    @tailrec
    def splitInner[A](res: List[List[A]], lst: List[A], n: Int) : List[List[A]] = {
      if(lst.isEmpty) res
      else {
        val headList: List[A] = lst.take(n)
        val tailList : List[A]= lst.drop(n)
        splitInner(headList :: res, tailList, n)
      }
    }

    splitInner(Nil, xs, n).reverse
  }

}

object ListSplitterTest extends App {
  val res = ListSplitter.split(List(1,2,3,4,5,6,7), 2)
  println(res)
}


답변

나는 이것이 take / drop 대신 splitAt을 사용하는 구현이라고 생각합니다.

def split [X] (n:Int, xs:List[X]) : List[List[X]] =
    if (xs.size <= n) xs :: Nil
    else   (xs.splitAt(n)._1) :: split(n,xs.splitAt(n)._2)


답변