복붙노트

[SCALA] 함수 프로그래밍 스칼라는지도 왼쪽 접어서 [마감]

SCALA

함수 프로그래밍 스칼라는지도 왼쪽 접어서 [마감]

배 왼쪽에 좋은 튜토리얼은 무엇입니까?

다른 답변에 대한 컨텍스트를 제공하기 위해 삭제에서 복원 원래 질문 :

나는 사각형, 원, 위치의 경계 상자와 모든 모양을 확장 그룹을 찾기위한 방법을 구현하기 위해 노력하고 있습니다. 그룹은 기본적으로 모양의 배열입니다

abstract class Shape  
case class Rectangle(width: Int, height: Int) extends Shape  
case class Location(x: Int, y: Int, shape: Shape) extends Shape  
case class Circle(radius: Int) extends Shape  
case class Group(shape: Shape*) extends Shape  

나는 그룹 제외한 모든 세 가지에 대해 계산 된 경계 상자를 얻었다. 이제 경계 상자 방법에 대해 내가지도를 이용해야하며, 그룹 왼쪽 접어서 알고 있지만 난 그냥 그것을 만드는 정확한 구문을 찾을 수 없습니다.

object BoundingBox {  
  def boundingBox(s: Shape): Location = s match {  
    case Circle(c)=>   
      new Location(-c,-c,s)  
    case Rectangle(_, _) =>  
      new Location(0, 0, s)  
    case Location(x, y, shape) => {  
      val b = boundingBox(shape)  
      Location(x + b.x, y + b.y, b.shape)  
    }  
    case Group(shapes @ _*) =>  ( /: shapes) { } // i dont know how to proceed here.
  }
}

그룹 경계 상자는 기본적으로 둘러싸인 모양 모두 가장 작은 경계 상자입니다.

해결법

  1. ==============================

    1.이제 거의 완전히 다른 질문을 편집 한 것으로, 내가 다른 대답을 줄 수 있습니다. 오히려지도 및 주름에 대한 자습서를 가리킨 것보다, 그냥 하나를 줄 것이다.

    이제 거의 완전히 다른 질문을 편집 한 것으로, 내가 다른 대답을 줄 수 있습니다. 오히려지도 및 주름에 대한 자습서를 가리킨 것보다, 그냥 하나를 줄 것이다.

    스칼라 먼저 익명 함수를 만드는 방법을 알 필요가있다. 그것은 가장 일반적인에서 더 구체적으로,과 같이 간다 :

    (var1: Type1, var2: Type2, ..., varN: TypeN) => /* output */
    (var1, var2, ..., varN) => /* output, if types can be inferred */
    var1 => /* output, if type can be inferred and N=1 */
    

    여기 몇 가지 예가 있어요.

    (x: Double, y: Double, z: Double) => Math.sqrt(x*x + y*y + z*z)
    val f:(Double,Double)=>Double = (x,y) => x*y + Math.exp(-x*y)
    val neg:Double=>Double = x => -x
    

    이제지도 목록의 방법 및지도의 모든 요소에 함수 (익명 또는 기타)를 적용합니다. 당신이있는 경우 즉,

    List(a1,a2,...,aN)
    f:A => B
    

    그때

    List(a1,a2,...,aN) map (f)
    

    생산

    List( f(a1) , f(a2) , ..., f(aN) )
    

    이 유용 할 수 있습니다 모든 종류의 이유들이 존재한다. 어쩌면 당신은 문자열의 무리가 있고 각이 얼마나 오래 알고 싶어하거나 그들에게 모두 대문자을 만들고 싶어하거나 뒤로를 원한다. 당신은 하나 개의 요소에 당신이 원하는 것을 수행하는 기능이있는 경우,지도는 모든 요소에 그것을 할 것입니다 :

    scala> List("How","long","are","we?") map (s => s.length)
    res0: List[Int] = List(3, 4, 3, 3)
    
    scala> List("How","capitalized","are","we?") map (s => s.toUpperCase)
    res1: List[java.lang.String] = List(HOW, CAPITALIZED, ARE, WE?)
    
    scala> List("How","backwards","are","we?") map (s => s.reverse)
    res2: List[scala.runtime.RichString] = List(woH, sdrawkcab, era, ?ew)
    

    그래서, 그의는 일반적으로지도하고, 스칼라있다.

    그러나 우리는 우리의 결과를 수집 할 경우 어떻게? 배에 오는 그의는 (foldLeft 왼쪽에 시작하고 잘 작동하는 버전이다).

    우리는 함수 f 있다고 가정 (B, A) => B는, 즉, 그들에 B. 음을 생성하는 B 및 A, 및 콤바인 소요을 우리는 B로 시작하는 다음의 목록을 공급할 수있다 A의 그것을 한 번에 한에, 그리고 모든 말에, 우리는의 배 않습니다 정확히 몇 가지 B.이있을 것이다. foldLeft는 목록의 왼쪽 끝에서 시작합니다; foldRight이 (가) 오른쪽에서 시작됩니다. 그건,

    List(a1,a2,...,aN) foldLeft(b0)(f)
    

    생산

    f( f( ... f( f(b0,a1) , a2 ) ... ), aN )
    

    어디 B0는 초기 값, 물론입니다.

    그래서, 어쩌면 우리는 INT와 문자열을 사용하고, INT 또는 중 큰 문자열의 길이를 반환하는 함수가 - 우리가 그것을 사용하여 목록을 접어 경우를, 그것은 우리에게 가장 긴 문자열 (가정을 말할 것 우리가 ) 0로 시작합니다. 또는 우리는 우리가가는대로 값을 축적의 INT에 길이를 추가 할 수 있습니다.

    의 그것을 시도 줘 보자.

    scala> List("How","long","is","longest?").foldLeft(0)((i,s) => i max s.length) 
    res3: Int = 8
    
    scala> List("How","long","is","everyone?").foldLeft(0)((i,s) => i + s.length)
    res4: Int = 18
    

    좋아, 좋아,하지만 우리가 알고 싶다면 것은 가장 긴 누구인가? 한 가지 방법은 (아마도없는 최고의하지만 잘 유용한 패턴을 보여줍니다)의 길이 (정수) 및 주요한 경쟁자 (문자열)을 모두 함께 수행하는 것입니다. 갈 그하자주고 :

    scala> List("Who","is","longest?").foldLeft((0,""))((i,s) => 
         |   if (i._1 < s.length) (s.length,s)
         |   else i
         | )
    res5: (Int, java.lang.String) = (8,longest?)
    

    여기서, I 형의 튜플 (INT, 문자열)은 이제이고, i._1는 튜플 (정수)의 첫 번째 부분이다.

    그러나이 같은 경우에, 폴드를 사용하는 것은 정말 우리가 원하는하지 않습니다. 우리는 더 이상 두 개의 문자열을 원하는 경우, 가장 자연스러운 기능은 최대처럼 하나가 될 것입니다 : (문자열, 문자열) => 문자열. 우리는 어떻게 그 일을 적용합니까?

    우리는 ""로 시작하는 문자열 최대 기능을 접을 수 있도록 음,이 경우, 기본 "짧은"경우가 있습니다. 그러나 더 좋은 방법은 줄이고 사용하는 것입니다. 배와 같이 두 가지 버전, 왼쪽에서 작동 하나, 오른쪽에서 작동하는 다른있다. 그것은 어떤 초기 값을 취하며 함수 f 요구 (A, A) =>을한다. 즉, 두 가지 반환 동일한 유형 중 하나를 취합니다. 다음은 문자열 최대 기능을 예입니다 :

    scala> List("Who","is","longest?").reduceLeft((s1,s2) =>              
         |   if (s2.length > s1.length) s2
         |   else s1
         | )
    res6: java.lang.String = longest?
    

    이제 두 더 트릭이있다. 먼저, 다음과 같은 두 가지가 동일한 것을 의미 :

    list.foldLeft(b0)(f)
    (b0 /: list)(f)
    

    주의 두 번째는 짧은이며, 그것은 일종의 당신에게 인상을 준다 어떻게 당신이있는 거 복용 B0와 (당신이) 그것으로 목록에 뭔가를하고. (가 : \ foldRight과 동일하지만, 그렇게처럼 사용합니다 (목록 : \ B0) (F)를

    한 번만 변수를 참조하는 경우 둘째, 당신은 변수 이름 대신 _ 사용하고 익명 함수 선언의 x => 일부를 생략 할 수 있습니다. 여기에 두 가지 예는 다음과 같습니다

    scala> List("How","long","are","we?") map (_.length)
    res7: List[Int] = List(3, 4, 3, 3)
    
    scala> (0 /: List("How","long","are","we","all?"))(_ + _.length)
    res8: Int = 16
    

    이 시점에서 함수를 만들고지도, 배, 그리고 스칼라를 사용하여 감소 할 수 있어야한다. 당신이 당신의 알고리즘이 작동하는 방법을 알고있는 경우에 따라서, 합리적를 ​​구현하기 간단합니다.

  2. ==============================

    2.기본 알고리즘은 다음과 같이 갈 것입니다 :

    기본 알고리즘은 다음과 같이 갈 것입니다 :

    shapes.tail.foldLeft(boundingBox(shapes.head)) {
      case (box, shape) if box contains shape => box
      case (box, shape) if shape contains box => shape
      case (box, shape) => boxBounding(box, shape)
    }
    

    쓰기가 포함하고 순수한 알고리즘 문제보다 언어 문제보다 boxBounding에 이제 당신은.

    모양이 모두 같은 중심이 있다면, 포함 구현하는 것은 쉬울 것이다. 그것은 다음과 같이 갈 것입니다 :

    abstract class Shape { def contains(s: Shape): Boolean }
    case class Rectangle(width: Int, height: Int) extends Shape {
      def contains(s: Shape): Boolean = s match {
        case Rectangle(w2, h2) => width >= w2 && height >= h2
        case Location(x, y, s) => // not the same center
        case Circle(radius) => width >= radius && height >= radius
        case Group(shapes @ _*) => shapes.forall(this.contains(_))
      }
    }
    case class Location(x: Int, y: Int, shape: Shape) extends Shape {
      def contains(s: Shape): Boolean = // not the same center
    }
    case class Circle(radius: Int) extends Shape {
      def contains(s: Shape): Boolean = s match {
        case Rectangle(width, height) => radius >= width && radius >= height
        case Location(x, y) => // not the same center
        case Circle(r2) => radius >= r2
        case Group(shapes @ _*) => shapes.forall(this.contains(_))
      }
    }
    case class Group(shapes: Shape*) extends Shape {
      def contains(s: Shape): Boolean = shapes.exists(_ contains s)
    }
    

    이 개 모양을 소요하고 그들을 결합 boxBounding,에 관해서는, 일반적으로 직사각형 수 있지만 특정 circunstances 아래 원이 될 수 있습니다. 당신이 알고리즘이 파악 일단 어쨌든 꽤 솔직하다.

  3. ==============================

    3.경계 상자는 일반적으로 직사각형이다. 나는 ....에 위치한 원 (-r, -r) 반경 r의 원의 경계 상자라고 생각하지 않습니다

    경계 상자는 일반적으로 직사각형이다. 나는 ....에 위치한 원 (-r, -r) 반경 r의 원의 경계 상자라고 생각하지 않습니다

    어쨌든, 당신은 경계 상자 B1과 다른 B2와 B1 및 B2의 경계 상자를 계산하는 기능 combineBoxes이 있다고 가정합니다.

    당신이 당신의 그룹 형태의 비어 있지 않은 설정이있는 경우 다음, 당신은 하나의 거대한 상자 남을 때까지 한 번에 두 가지를 결합하여 경계 상자의 목록의 전체 경계 상자를 계산하는 reduceLeft를 사용할 수 있습니다. (같은 아이디어는 쌍으로 추가하여 숫자의 합 번호 목록을 줄일 수 있습니다. 그리고이 목록에서 왼쪽에서 오른쪽으로 작동하기 때문에 그것은 reduceLeft을 불렀다.)

    blist 각 모양의 경계 상자의 목록입니다 있다고 가정하자. (힌트 : 맵이 들어오는 곳이다.) 그리고

    val bigBox = blist reduceLeft( (box1,box2) => combineBoxes(box1,box2) )
    

    당신은 그러나, 별도로 빈 그룹 사건을 잡을해야합니다. 주름이 의미가 기본 비어있는 경우가있는 경우에 좋다 또는 당신은 옵션으로 접어해야하지만, 다음 결합하는 기능을 가지고, 그것은 노 잘 정의 된 경계 상자를 가지고 있기 때문에 (, 당신은 사용 주름을 원하지 않는다. 아마이 경우 가치가없는 일부 (상자)과 없음을 결합하지하는 방법을 이해합니다 -.하지만 우아에 요구 빈 목록 상황의 다양한 종류를 처리 할 것을 생산 코드를 작성한다면 매우 잘 수 있습니다)

  4. from https://stackoverflow.com/questions/2293592/functional-programming-scala-map-and-fold-left by cc-by-sa and MIT license