본문 바로가기
프로그래밍/함수형 프로그래밍

스칼라(Scala) 리스트에 대해서 알아보자

by bantomak 2024. 7. 23.
반응형

스칼라(Scala) 리스트

스칼라에서는 다음과 같이 List라는 키워드를 사용하여 리스트를 정의할 수 있다.

 

> val a = List(1, 2, 3)
a: List[Int] = List(1, 2, 3)

 

출력을 해보면 List[Int] 라고 출력되어 Int로 구성된 리스트가 만들어진 것을 알 수 있다. 또한, 다음과 같이 여러 종류의 타입으로 구성된 리스트를 만드는 것도 가능하다.

 

> val b = List(1, "2", 3.0)
b: List[Any] = List(1, 2, 3.0)

 

참고로,  Any는 모든 스칼라 타입의 부모이기 때문에 Any 타입의 변수에는 모든 타입의 값을 담는 것이 가능하다.

 

> val a:Any = 1
> val a:Any = "1"
> val a:Any = 2.0
> val a:Any = List(1, 2, 3)

 

Nil과 ::

스칼라에서는 Nil(빈 리스트)과 ::(콘즈)를 통해 리스트를 구성할 수 있다. 

 

> Nil
List()

> 1 :: Nil
List(1)

> 1 :: List(2, 3)
List(1, 2, 3)

> 1 :: (2 :: (3 :: Nil))
List(1, 2, 3)

 

::는 기본적으로 값 :: 리스트 형태로 사용된다. 따라서 1 :: 2와 같이 값만 가지고 사용하면 에러가 발생한다. 1 :: 2 :: Nil의 경우는 Nil이 빈 리스트이기 때문에 사용할 수 있다.

 

head와 tail

리스트에 있는 head라는 메서드는 리스트의 첫 번째 요소를 반환하며, tail은 첫 번째 요소를 제외한 나머지 리스트를 반환한다.

 

> List(1, 2, 3).head
1

> List(1, 2, 3).tail
List(2, 3)

 

head와 tail은 재귀 함수를 작성할 때 요긴하게 사용된다. List의 합을 구하는 재귀 함수는 다음과 같다.

 

def sumOfList(list: List[Int]): Int = {
    if (list == Nil) 0
    else list.head + sumOfList(list.tail)
}

> sumOfList(List(1, 2, 3))
6

 

입력 인자 List가 빈 리스트(Nil)이면 0을 반환하고, 그 이외에는 (리스트의 head 값 + 재귀 호출(리스트의 tail))을 반환한다.

 

연습문제

숫자로 구성된 리스트를 인자로 받아서 짝수인 숫자만 포함하는 리스트를 반환하는 filterOdd 함수를 재귀적으로 작성하라.

object Main extends App {
  // filterOdd 함수 정의
  def filterOdd(numbers: List[Int]): List[Int] = {
    numbers match {
      case Nil => Nil // 빈 리스트의 경우, 빈 리스트를 반환
      case head :: tail =>
        if (head % 2 == 0) head :: filterOdd(tail) // 짝수인 경우, 리스트에 추가
        else filterOdd(tail) // 홀수인 경우, 리스트에 추가하지 않음
    }
  }

  // 예시 리스트
  val nums = List(1, 2, 3, 4, 5, 6)

  // 함수 호출 및 결과 출력
  val result = filterOdd(nums)
  println(result)  // 출력: List(2, 4, 6)
}

 

리스트에 대한 패턴 매치

리스트는 head::tail로 구성된다. 즉, head는 리스트의 첫 번째 값이고 tail은 나머지 리스트를 가리킨다. 그러면 다음과 같이 리스트의 head와 tail을 변수에 할당하는 것이 가능하다.

 

> val head :: tail = List(1, 2, 3, 4 5)
> head
1
> tail
List(2, 3, 4, 5)

 

변수 head에는 리스트의 첫 번째 값이 배정되었고, tail에는 나머지 리스트가 배정되었다. 이를 패턴 매치에 사용할 수 있다.

 

> val list = List(1, 2, 3)
> list match {
    case Nil => println("empty")
    case head :: tail => println(head)
}
1

 

그럼, 앞서 작성했던 List의 합을 구하는 함수를 패턴 매칭을 사용하도록 수정해 보자.

 

> def sumOfList(list: List[Int]): Int = {
    list match {
        case Nil => 0
        case head :: tail => head + sumOfList(tail)
    }
}
> sumOfList(List(1, 2, 3, 4, 5))
15

 

list가 Nil일 때와 head :: tail일 때로 구분 지어 재귀 함수를 작성하였다. 재귀 함수를 정의할 때 패턴 매치를 사용하면 좀 더 구조적이고 세련된 코드가 되는 것을 알 수 있다.

 

참고 서적

 

함수형 언어 산책 - 예스24

함수형 언어와 빅 데이터 처리 프레임워크 학습을 위한 실습형 안내서이 책은 최초의 함수형 언어인 리스프(LISP)부터 리스프를 바탕으로 만들어진 강력한 에디터인 이맥스(Emacs), JVM 위에 되살아

www.yes24.com

댓글