2017-10-12 13 views
0

스칼라 꼬리 재귀에 대한 질문이 있습니다. 필자는 목록을 가져 와서 짝수 번호의 새로운 목록을 만드는 간단한 꼬리 재귀 코드를 작성했습니다. 그러나 scala가 요소를 목록에 추가 할 수 없기 때문에 목록이 내림차순으로 정렬됩니다. 아래의 코드스칼라에서 꼬리 재귀

def listCreator(lists: List[Int]): List[Int] = { 
    @tailrec 
    def evenListCreator(lists: List[Int], accum: List[Int]): List[Int] = { 
     lists match { 
      case Nil => accum 
      case x :: Nil if (isEven (x) == true) => x :: accum 
      case x :: Nil if (isEven (x) == false) => accum 
      case x :: tail if (isEven (x) == true) => evenListCreator(tail, x :: accum) 
      case x :: tail if (isEven (x) == false) => evenListCreator(tail, accum) 
     } 
    } 
    evenListCreator(lists, List()) 
} 

는 I가 다음과 같은 질문

  1. 나는이 방법에서 목록을 반전 성명을 추가 할 수 있습니까?

  2. 이 메서드 호출 바로 뒤에 오는 evenListCreator(lists, List()) 라인은 꼬리 재귀를 위해 필수입니까?

+0

'Vector'는 불변하지만 합리적으로 효율적 추가를 가지고 ... 이건 정말, 단지 학습 운동입니다 알고 있지만, 당신은 하하, 내가 어딘가에 시작했다 List' –

답변

2

되돌리기 전에 되돌릴 수 있습니다.

scala> def listCreator(lists: List[Int]): List[Int] = { 
    |  @tailrec 
    |  def evenListCreator(lists: List[Int], accum: List[Int]): List[Int] = { 
    |   lists match { 
    |    case Nil => accum 
    |    case x :: Nil if (isEven (x) == true) => x :: accum 
    |    case x :: Nil if (isEven (x) == false) => accum 
    |    case x :: tail if (isEven (x) == true) => evenListCreator(tail, x :: accum) 
    |    case x :: tail if (isEven (x) == false) => evenListCreator(tail, accum) 
    |   } 
    |  } 
    |  evenListCreator(lists, List.empty[Int]).reverse 
    | } 
listCreator: (lists: List[Int])List[Int] 

scala> listCreator((1 to 10).toList) 
res2: List[Int] = List(2, 4, 6, 8, 10) 

scala> 

당신은 즉시 메소드 호출을 수행 할 필요가 없습니다하지만 당신은 당신이 두 개의 인수를 보낼 필요하지 않으면 하나의 목록이며, 두 번째는 빈 목록입니다. 그래서 우리는 정수 목록 만 가지고 사용하는 사람이 빈 목록을 보내는 것처럼 귀찮게하지 않았습니다.

그리고 직접 또한 그것을 할 수

scala> val list = (1 to 10).toList 
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 

scala> list.map(_ * 2) 
res8: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20) 

scala> 
2
  1. evenListCreator(lists, List()).reverse 또는 evenListCreator(lists.reverse, List()),하지만 귀하의 경우 첫 번째 양식은 대부분 evenListCreator
  2. 에 전화 후 짧아집니다 반대하는 목록으로 더
  3. 이 줄 : evenListCreator(lists, List()) 메서드 호출을 따르지 않습니다, 메서드 호출입니다. 이 함수가 없으면 꼬리 재귀 함수 (def evenListCreator) 만 정의하고 호출하지 않고 리턴하면 아무 일도 일어나지 않습니다.

일부 다른 음

당신은 너무 많은 정지 조건을 가지고,이 충분하다 :

@tailrec 
def evenListCreator(lists: List[Int], accum: List[Int]): List[Int] = { 
    lists match { 
    case Nil => accum 
    case x :: tail if isEven (x) => evenListCreator(tail, x :: accum) 
    case x :: tail if !isEven (x) => evenListCreator(tail, accum) 
    } 
} 

당신에게 :

@tailrec 
def evenListCreator(lists: List[Int], accum: List[Int]): List[Int] = { 
    lists match { 
    case Nil => accum 
    case x :: tail if (isEven (x) == true) => evenListCreator(tail, x :: accum) 
    case x :: tail if (isEven (x) == false) => evenListCreator(tail, accum) 
    } 
} 

코드가 너무 장황,이 더 나은 생각 또한 재귀 함수를 다음과 같이 호출 할 수 있습니다.

evenListCreator(lists, Nil) 
2

Q1. @Mahesh Chand Kandpal이 지적했듯이 List을 반전하여 되돌릴 수 있습니다. 또는 사전 보류 ("cons") 메서드 대신 accum :+ x이라는 추가 메서드를 사용하여 목록을 작성할 수 있습니다. x :: accum.

그러나 List의 경우 cons 메서드가 append 메서드보다 효율적이므로 빌드 및 리버스하는 것이 일반적으로 좋습니다.

2. 아니요, 테일 재귀는 호출이 반환 된 후에 대기하는 다른 작업이 없다는 것을 의미합니다. 즉, return callMyself()은 꼬리 호출이지만 return callMyself() + 1은 그렇지 않습니다.

P.내가

def listCreator(ints: List[Int]): List[Int] = ints.filter(i => (i&1) < 1) 
+0

'대신에 그것을 사용할 수 있습니다 :) 당신의 도움을 주셔서 감사합니다 – Srinivas