본문 바로가기

Languages/Scala-99-Problems

Scala-99-Problems 솔루션 : P14 ~ P18

반응형

이미지 출처 : Pixabay

이전 포스팅과 같이 연관성 있는 문제가 아니라면 추후 포스팅부터는 5문제씩 끊어서 솔루션을 달 예정입니다 :)

시작할게요!


P14. 리스트의 원소들을 복제하는 함수를 작성하시오.

P14. Duplicate the elements of a list.

이 문제도 Head -> Tail로 이동하며 head를 두번씩 append하여 재귀적인 방법으로 쉽게 해결할 수 있습니다.

head :: tail 재귀를 사용한 배열 내 원소 복제

소스 코드는 다음과 같습니다 :

def duplicate[T](list: List[T]): List[T] = list match {
  case Nil => Nil
  case head :: tail => head :: head :: duplicate(tail)
}

P15. 리스트의 원소들을 주어진 숫자만큼 복제하는 함수를 작성하시오.

P15. Duplicate the elements of a list a given number of times.

P14와 유사하지만 복제하는 횟수가 주어진 문제입니다.

주어진 숫자를 n이라고 할 때, 0..n의 range 컬렉션을 생성한 다음 각 컬렉션의 원소를 map 함수를 사용하여 복제할 원소(head)로 매핑해 준다음 리스트로 변환하여 tail을 append 해 줍니다.

range(...) map (_ => head) toList 를 활용한 n번 복제

소스 코드는 다음과 같습니다 : 

def duplicateN[T](n: Int, list: List[T]): List[T] = list match {
  case Nil => Nil
  case head :: tail => ((0 until n) map (_ => head)).toList ::: duplicateN(n, tail)
}

P16. 리스트에서 모든 N번째 원소를 제거하는 함수를 작성하시오. (예) N=3일때, 3, 6, 9 ... 번째 원소를 제거

P16. Drop every Nth element from a list.

이 문제는 리스트에서 N번째마다 오는 함수를 제거해야 하는 문제입니다.

tail에서 drop 함수와 take 함수를 조합하여 해결합니다.

주어진 n에 대해서, n이 1보다 크다면 Tail의 앞에서 n-2만큼을 take하여 Head에 append한 다음, Tail의 n-1을 drop하여 drop함수 재귀호출의 인자로 사용합니다.

만약 n이 3이라면 tail.take(1), drop(3, tail.drop(2)) 를 통해 n번째, 즉 3번째에 위치한 원소를 제거할 수 있습니다.

마찬가지로 n이 4라면 Tail의 앞에서 2개의 원소를 취하고, 다음 재귀호출의 인자로 Tail의 앞에서 3개의 원소를 버린 것을 넘겨준다면 결과적으로 4번째 원소가 삭제됩니다.

Tail.take Tail.drop 함수의 조합으로 해결

소스 코드는 다음과 같습니다 :

def drop[T](n: Int, list: List[T]): List[T] = list match {
  case Nil => Nil
  case head :: tail => if (n > 1) head :: tail.take(n - 2) ::: drop(n, tail.drop(n - 1)) else Nil
}

P17. 리스트를 두 부분으로 분리하는 함수를 작성하시오. 첫 부분의 길이는 입력으로 주어지며, 결과를 튜플 형태로 반환하시오.

P17. Split a list into two parts. The length of the first part is given. Use a Tuple for your result.

이 문제는 재귀적으로 해결하지 않고, 이미 구현된 take, takeRight 함수를 사용하여 해결합니다.

이전 문제와 비슷하게 take와 takeRight 함수로 리스트를 분리한 다음 튜플로 조합하여 반환하는 방법으로 해결합니다. 첫 부분의 길이 n이 리스트 전체의 길이보다 크다면 IndexOutOfBoundsException을 던져줍니다.

list.takeLeft(), list.takeRight() 함수의 활용

소스 코드는 다음과 같습니다 :

def split[T](n: Int, list: List[T]): (List[T], List[T]) = {
  if (n >= list.length) throw new IndexOutOfBoundsException
  else (list.take(n), list.takeRight(list.length - n))
}

P18. 리스트에서 조각(slice)를 추출하는 함수를 작성하시오. 두 개의 인덱스 I, K가 입력으로 주어지며, 추출된 조각은 I번째 원소부터 K번째 원소 직전까지를 포함, [I,K) 하도록 작성한다. 리스트의 인덱스는 0번부터 시작한다.

P18. Extract a slice from a list. Given two indices, I and K, the slice is the list containing the elements from and including the Ith element up to but not including the Kth element of the original list. Start counting the elements with 0.

이번 문제도 재귀적으로 작성하지 않고 take ~ 함수를 사용하여 해결합니다.

만약 주어진 인덱스를 i, j라 한다면, 전체 배열의 길이 l에서 l-i만큼을 takeRight한 다음, 여기서 다시 j만큼을 take합니다.

앞에서 i만큼을, 뒤에서 length-k 만큼을 truncate한 것과 똑같은 동작이 수행되어 [I,K) 범위로 배열을 슬라이스할 수 있습니다.

takeRight(), take() 함수의 활용

소스 코드는 다음과 같습니다 :

def slice[T](i: Int, k: Int, list: List[T]): List[T] = {
  if ((i >= list.length) && (k >= list.length) && (i > k)) throw new IndexOutOfBoundsException
  else list.takeRight(list.length - i).take(k - i)
}

 

반응형