답변:
그것은에서 사용되는 시퀀스 함축 (당신이 사용할 수 파이썬의리스트 지능형 발전기처럼 yield
너무).
for
새로운 요소와 조합하여 적용되며 결과 시퀀스에 새 요소를 씁니다.
간단한 예 ( scala-lang )
/** Turn command line arguments to uppercase */
object Main {
def main(args: Array[String]) {
val res = for (a <- args) yield a.toUpperCase
println("Arguments: " + res.toString)
}
}
F #의 해당 표현식은
[ for a in args -> a.toUpperCase ]
또는
from a in args select a.toUpperCase
Linq.
루비 yield
는 다른 효과가 있습니다.
나는 대답이 훌륭하다고 생각하지만 많은 사람들이 근본적인 요점을 파악하지 못한 것 같습니다.
첫째, 스칼라의 for
이해는 하스켈의 이해와 동일합니다.do
표기법 , 여러 모나드 연산의 구성을위한 구문 설탕에 지나지 않습니다. 이 문장은 도움이 필요한 사람에게는 도움이되지 않을 것이므로 다시 시도합시다… :-)
스칼라의 for
함축은지도 여러 작업의 구성에 대한 문법 설탕이다, flatMap
하고 filter
. 또는 foreach
. 스칼라는 실제로 for
-expression을 해당 메소드에 대한 호출로 변환 하므로이를 제공하는 클래스 또는 서브 세트를 이해하기 위해 사용할 수 있습니다.
먼저 번역에 대해 이야기합시다. 매우 간단한 규칙이 있습니다.
이
for(x <- c1; y <- c2; z <-c3) {...}
로 번역
c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))
이
for(x <- c1; y <- c2; z <- c3) yield {...}
로 번역
c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
이
for(x <- c; if cond) yield {...}
스칼라 2.7에서
c.filter(x => cond).map(x => {...})
스칼라 2.8에서
c.withFilter(x => cond).map(x => {...})
방법을 withFilter
사용할 수 없지만 가능한 경우 전자에 폴백합니다 filter
. 이에 대한 자세한 내용은 아래 섹션을 참조하십시오.
이
for(x <- c; y = ...) yield {...}
로 번역
c.map(x => (x, ...)).map((x,y) => {...})
매우 간단한 for
이해를 보면 map
/ foreach
대안이 실제로 더 좋습니다. 그러나 작성을 시작하면 괄호와 중첩 수준에서 쉽게 길을 잃을 수 있습니다. 그렇게되면 for
이해력이 훨씬 명확 해집니다.
간단한 예를 하나 보여 드리고 의도적으로 설명을 생략하겠습니다. 이해하기 쉬운 구문을 결정할 수 있습니다.
l.flatMap(sl => sl.filter(el => el > 0).map(el => el.toString.length))
또는
for {
sl <- l
el <- sl
if el > 0
} yield el.toString.length
withFilter
Scala 2.8에는이라는 메소드가 도입되었으며 withFilter
, 주요 차이점은 필터링 된 새 컬렉션을 반환하는 대신 요청시 필터링한다는 점입니다. 이 filter
방법은 컬렉션의 엄격성에 따라 동작이 정의됩니다. 이것을 더 잘 이해하려면 List
(엄격한) 및 Stream
(엄격하지 않은 ) 스칼라 2.7을 살펴 보겠습니다 .
scala> var found = false
found: Boolean = false
scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9
scala> found = false
found: Boolean = false
scala> Stream.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
때문에 차이가 발생하는 filter
즉시 적용되어 List
있기 때문에 - 확률의 목록을 반환 found
이다 false
. 그래야만 foreach
실행되지만, 지금까지는 이미 실행 된 found
것처럼 변경 이 의미가 없습니다 filter
.
의 경우 Stream
조건이 즉시 적용되지 않습니다. 각각의 요소에 의해 요구되는 바와 같이 대신 foreach
, filter
수 조건, 테스트 foreach
를 통해 영향을 found
. 명확히하기 위해 여기에 해당하는 이해력 코드가 있습니다.
for (x <- List.range(1, 10); if x % 2 == 1 && !found)
if (x == 5) found = true else println(x)
for (x <- Stream.range(1, 10); if x % 2 == 1 && !found)
if (x == 5) found = true else println(x)
사람들은 if
사전에 전체 컬렉션에 적용되는 대신 주문형으로 간주 되기 때문에 많은 문제가 발생 했습니다.
도입 스칼라 2.8 withFilter
입니다, 항상 비 엄격한은 더 컬렉션의 엄격 상관 없습니다. 다음 예제는 List
Scala 2.8에서 두 가지 방법을 모두 보여줍니다 .
scala> var found = false
found: Boolean = false
scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9
scala> found = false
found: Boolean = false
scala> List.range(1,10).withFilter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
이것은 filter
동작 을 바꾸지 않고 대부분의 사람들이 기대하는 결과를 만들어냅니다 . 참고로 Range
Scala 2.7과 Scala 2.8 사이에서 엄격하지 않음에서 엄격으로 변경되었습니다.
withFilter
엄격한 컬렉션의 경우에도 엄격하지 않아야하며 설명이 필요합니다. 나는 이것을 고려할 것이다 ...
for(x <- c; y <- x; z <-y) {...}
로 변환됩니다 c.foreach(x => x.foreach(y => y.foreach(z => {...})))
2.하기 for(x <- c; y <- x; z <- y) yield {...}
로 번역c.flatMap(x => x.flatMap(y => y.map(z => {...})))
for(x <- c; y = ...) yield {...}
정말로로 번역 c.map(x => (x, ...)).map((x,y) => {...})
됩니까? 번역 c.map(x => (x, ...)).map(x => { ...use x._1 and x._2 here...})
된 것 같아요. 뭔가 빠졌나요?
예, Earwicker가 말했듯이 LINQ select
와 거의 동일 하며 Ruby 및 Python과 거의 관련이 없습니다 yield
. 기본적으로 C #에서 작성하는 위치
from ... select ???
스칼라에서는 대신에
for ... yield ???
for
-comprehensions는 시퀀스에서만 작동하는 것이 아니라 LINQ와 같이 특정 메소드를 정의하는 모든 유형에서 작동 한다는 것을 이해하는 것이 중요합니다 .
map
을 허용 for
합니다.flatMap
뿐만 아니라를 정의 map
하면 for
여러 생성기로 구성된 표현식 을 허용 합니다.foreach
하면 for
수율없이 단일 루프와 다중 생성기를 사용하여 -loops를 허용 합니다.filter
, 그것은 수 for
로 시작 -filter 표현 if
의 for
표현.Scala 사용자로부터 더 나은 답변을 얻지 못하면 (내가 아님), 여기 내 이해가 있습니다.
for
기존 목록에서 새 목록을 생성하는 방법을 나타내는으로 시작하는 표현식의 일부로 만 나타납니다 .
다음과 같은 것 :
var doubled = for (n <- original) yield n * 2
따라서 각 입력에 대해 하나의 출력 항목이 있습니다 (중복을 삭제하는 방법이 있다고 생각하지만).
이것은 거의 모든 구조를 가진 일부 명령 코드에서 길이의 목록을 생성하는 방법을 제공하는 다른 언어의 yield로 활성화 된 "제한 연속"과는 매우 다릅니다.
(C #에 익숙하다면 LINQ select
연산자보다 LINQ 연산자에 더 가깝 습니다 yield return
).
키워드 yield
스칼라는 단순히 문법 설탕입니다 쉽게 교체 할 수 있습니다 map
로, 다니엘 소브랄 이미 설명 자세히.
반면에, yield
절대적 경우 오해의 소지가있다 파이썬 과 유사한 생성기 (또는 연속체)를 찾고 . 자세한 내용은이 SO 스레드를 참조하십시오. Scala에서 '수율'을 구현하는 기본 방법은 무엇입니까?
다음과 같은 이해력을 고려하십시오
val A = for (i <- Int.MinValue to Int.MaxValue; if i > 3) yield i
다음과 같이 큰 소리로 읽는 것이 도움이 될 수 있습니다
" 위해 각각의 정수 i
, 만약 그것보다 큰 3
후 수율 (생산) i
과 목록에 추가A
."
수학적 set-builder 표기법 측면 에서 위의 이해력은 다음과 유사합니다.
로 읽을 수 있습니다
" 위해 각각의 정수 , 만약 그것보다 크면 , 그것은 구성원 세트 중 ."
또는 대안으로
" 는 모든 정수의 집합 이므로 각각 이보다 큽니다 ."
수율은 우리가 볼 수없는 버퍼를 가지고 있고 각 증가마다 버퍼에 다음 항목을 계속 추가하는 for 루프와 유사합니다. for 루프가 실행을 마치면 생성 된 모든 값의 컬렉션을 반환합니다. 수율은 간단한 산술 연산자로 사용하거나 배열과 함께 사용할 수도 있습니다. 이해를 돕기위한 두 가지 간단한 예가 있습니다.
scala>for (i <- 1 to 5) yield i * 3
입술 : scala.collection.immutable.IndexedSeq [Int] = 벡터 (3, 6, 9, 12, 15)
scala> val nums = Seq(1,2,3)
nums: Seq[Int] = List(1, 2, 3)
scala> val letters = Seq('a', 'b', 'c')
letters: Seq[Char] = List(a, b, c)
scala> val res = for {
| n <- nums
| c <- letters
| } yield (n, c)
res : Seq [(Int, Char)] =리스트 ((1, a), (1, b), (1, c), (2, a), (2, b), (2, c), ( 3, a), (3, b), (3, c))
도움이 되었기를 바랍니다!!
val aList = List( 1,2,3,4,5 )
val res3 = for ( al <- aList if al > 3 ) yield al + 1
val res4 = aList.filter(_ > 3).map(_ + 1)
println( res3 )
println( res4 )
이 두 코드는 동일합니다.
val res3 = for (al <- aList) yield al + 1 > 3
val res4 = aList.map( _+ 1 > 3 )
println( res3 )
println( res4 )
이 두 코드도 동일합니다.
지도는 수확량만큼 유연하고 그 반대도 마찬가지입니다.
수율이 map ()보다 더 유연합니다 (아래 예 참조).
val aList = List( 1,2,3,4,5 )
val res3 = for ( al <- aList if al > 3 ) yield al + 1
val res4 = aList.map( _+ 1 > 3 )
println( res3 )
println( res4 )
yield는 List (5, 6)과 같은 결과를 출력합니다.
반면 map ()은 List (false, false, true, true, true)와 같은 결과를 반환합니다.