답변:
나는 당신이 찾고 있다고 생각합니다 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))
또는 직접 만들고 싶다면 :
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 년 후이 구현을 검토 할 때 size
O (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)
}
xs splitAt n
조합의 대안 xs take n
및xs drop n
splitAt
대신에 take
/ drop
4 %의 주위에 평균 성능을 향상; 둘 다 700-1000 % 더 빠릅니다 .grouped(n).toList
!
grouped-toList
그렇게 느린 지에 대한 생각 이 있습니까? 버그처럼 들립니다.
grouped
존재하지 않은 경우 :))의 경우 단순성이 최우선 요소입니다. 표준 라이브러리의 경우 안정성과 성능이 우아함을 능가해야합니다. 그러나 Programming in Scala 와 Normal-recursive (꼬리 재귀가 아닌) 호출의 표준 라이브러리 에는 많은 예제 가 있습니다. FP 도구 상자에서 표준적이고 중요한 무기입니다.
꼬리 재귀 대 재귀에 대한 논의가 있었기 때문에 분할 방법의 꼬리 재귀 버전을 추가하고 있습니다. 나는 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)
}