2013-01-30 3 views
4

나는이 : 그것은 스트림의 첫 번째 true 값을 발견하면이 종료됩니다 foldLeft 스트림에서 조기 종료 [부울]?

val b = a.foldLeft(false)(_||_) 

을 다음과 같이 내가 foldLeft

val a : Stream[Boolean] = ... 

? 그렇지 않다면 어떻게해야합니까?

+2

@ stew의 대답은 정상적인 방법입니다. 그러나 초기 단계에서 권장되는 방법을 찾고 있다면 더 일반적인 대답을 얻을 수 있습니다. http://stackoverflow.com/questions/12892701/abort-early-in-a-fold. – rjsvaljean

답변

2

처음 true 일 때는 종료되지 않습니다. 당신이 사용할 수있는 대신 존재합니다

val b = a.exists(identity) 
+0

@Duc가 게시 한 코드는 단지 설명이며 실제 사용 사례에서는 값을 어떤 식 으로든 누적해야한다고 확신합니다. 따라서 '존재한다'는 법안에 맞지 않는다. –

+0

@ RégisJean-Gilles 사용할 수없는 부울 값을 누적하는 방법은 무엇입니까? – stew

+0

실제 사용 사례로, 나는 그가 단지 스트림을 부울로하고 싶지 않은 경우를 의미했습니다. –

3

없음 조기 종료되지 않습니다. 이 설명하기 쉬운 :

val b = a.contains(true) 
:

val a : Stream[Boolean] = Stream.continually(true) 
// won't terminate because the strea 
val b = a.foldLeft(false)(_||_) 

스튜 간단한 솔루션이 특정 경우, 조기 종료하는 것으로 나타났다

val b = a.exists(identity). 

도 간단하다, 이것은 동일합니다

당신이 실제로 fold를 필요로한다면 위의 것과는 다른 좀 더 일반적인 해결책은 재귀를 사용하는 것입니다 (여기서 간단히하기 위해 스트림은 비어 있지 않다고 가정합니다) :

def myReduce(s: Stream[Boolean]): Boolean = s.head || myReduce(s.tail) 
val b = myReduce(a) 

지금 재귀 솔루션의 흥미로운 점은 그것이 당신이 실제로 (배입니다 무엇을하는) 어떤 방법으로 값을 축적 할 필요가보다 일반적인 사용 사례에 을 사용하고 여전히 종료 할 수있는 방법입니다 이른. add 메서드를 사용하여 int의 스트림 값을 추가하려는 경우 ||과 비슷한 방식으로 "종결"합니다 (이 경우 왼쪽면이> 100이면 오른쪽면을 평가하지 않습니다.) :

def add(x: Int, y: => Int) = if (x >= 100) x else x + y 
val a : Stream[Int] = Stream.range(0, Int.MaxValue) 
val b = a.foldLeft(0)(add(_, _)) 

마지막 행은 예제와 매우 유사합니다. 그러나이 같은 문제를 해결할 수 있습니다

def myReduce(s: Stream[Int]): Int = add(s.head, myReduce(s.tail)) 
val b = myReduce(a) 

경고이 :하지만이 방법에 큰 단점이있다 : myReduce 여기 꼬리 재귀가 아니라, 당신의 스택을 날려 것을 의미하는 경우의 반복하는 동안 너무 많은 요소 스트림. 아직 NTO 스택을 날려 않는 다른 솔루션은 이것이다 :

val b = a.takeWhile(_ <= 100).foldLeft(0)(_ + _) 

하지만 내가이 주제를 벗어 측에 정말 너무 멀리 갔다 두려워하는, 그래서 지금 더 나은 정지를 것입니다.

+0

당신이 작성한 것은'foldRight'입니다. 어쨌든 Stream에서는 tail-recursive가 아닙니다. foldRight에 대한 솔루션은 [이 답변] (http://stackoverflow.com/a/12893459/53974)을 참조하십시오. foldRight는 실제 폴드 기능을 매개 변수로 유지하면서 사용했던 아이디어를 일반화합니다. – Blaisorblade

+0

링크를 제공해 주셔서 감사합니다. 나는 대답을 다시하지 않을 것이다. 나는 나의 대답이 이미 거의 주제를 벗어나고 있다고 말했다. 내 대답과 연결된 응답을 사용하면 누구에게나 충분할 것입니다. 또한 믿거 나 말거나, 그러나'myReduce' (부울 스트림에 적용된 것)의 첫 번째 버전은 실제로 꼬리 재귀 적입니다. (두번째와의 주요 차이점은'||'는 내장 된 * 단락 연산자입니다)! –

+0

나는 당신의 의견에 자신을 의지하고 있었다. 그러나 나는 당신의 요점을 보았습니다 :'||'는 결국 shortcircuiting (자바에 의해 행해진 것)과 같은 바이트 코드로 컴파일되어야합니다. 따라서 그것은 꼬리 재귀 적입니다. 그리고 스칼라가이를 올바르게 구현합니다. 다소 놀랍게도 : 'import annotation.tailrec; @tailrec def myReduce (s : Stream [부울]) : 부울 = s.head || myReduce (s.tail)' – Blaisorblade

1

takeWhile을 사용하여 Stream의 접두사를 추출한 다음 foldLeft을 적용 할 수 있습니다.

관련 문제