개발을 시작하시는 여러분, 정보가 너무 많고 배워야 할 것도 산더미라 어디서부터 시작해야 할지 막막하신가요? 내일배움캠프 수료생들이 4개월 동안 배운 엄선된 핵심 개념을 직접 정리해서 알려 드립니다. 공부하다 막히거나 헷갈리는 개념이 있다면 개념 콕으로 정리해보세요.
코딩 테스트 문제를 풀 때면 여러 가지 값들을 다양한 기준으로 정렬해야 하는 경우가 많습니다. 이번에는 코딩 테스트 문제를 넘어 여러 가지 상황에서 적절한 정렬을 수행할 수 있도록, Kotlin에서 사용되는 정렬 메서드들을 알아보며, 어떻게 사용해야 하는지 알아보고자 합니다.
정렬이란?
Kotlin의 데이터 타입 중 Collection타입의 값은 유동적인 값을 다루기 위해 사용됩니다. (Array, List, Set, Map 등) 이중 인덱스를 기반으로 값을 저장하는 Array나 List, Set 같은 타입의 값들은 해당 값이 가지고 있는 원소들을 특정 기준으로 정렬하는 게 가능합니다. (Map의 경우는 sortedMap() 같은 메서드를 사용해 정렬된 맵을 다시 만들 수 있지만 직접적으로 정렬 메서드를 사용할 수는 없습니다.)
sort(), sorted()
기본적으로 Collection에 sort() 메서드를 사용하게 되면 해당 값들을 오름차순으로 정렬해 줍니다. 이때 sort()를 사용하면 전달받은 컬렉션 자체의 순서를 변경하고, sorted()를 사용하면 새로운 컬렉션 값을 생성해 순서를 변경하게 됩니다. 만약 전달받은 함수에서 외부의 값을 변경하면 안 되는 경우에는 sorted()를 사용해야 합니다.
그리고 아주 당연하게도 sort()의 경우 값에 대한 오름차순 기능만을 지원하기 때문에 정렬 기준을 알 수 없는 기본 타입 외의 컬렉션에 대해서는 사용이 불가능합니다.
(String, Int, Char같은 기본 타입이 아닌 직접 생성한 클래스 같은 경우 정렬 기준을 알기 힘들기 때문에 사용이 불가능합니다. 만약 사용하려면 Comparable 인터페이스를 구현해야 사용이 가능합니다.)
sortDescending(), sortedDescending()
sort()의 경우 오름차순으로 정렬한다면 sortDescending()은 대상을 내림차순으로 정렬합니다. 그 외에는 sort()와 sorted()의 차이와 같습니다. (이후 모든 정렬 메서드들은 Descending을 붙이면 내림차순이 됩니다.)
Comparator
여러 가지 정렬 기준을 사용해 정렬을 하려면 우선 기본적으로 Comparator에 대해서 알아야 합니다.
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fprod-files-secure.s3.us-west-2.amazonaws.com%252F83c75a39-3aba-4ba4-a792-7aefe4b07895%252F188db3c8-4614-4350-9381-d7f88cb2b651%252FUntitled.png%3Ftable%3Dblock%26id%3D9615c672-968e-43f2-8b5f-49bd7a3506f9%26cache%3Dv2&w=3840&q=75)
Comparator는 의미 그대로 두 가지 값을 비교하는 역할을 합니다. Kotlin에서 Comparator는 (T!, T!) -> Int 형태의 함수 타입 값을 전달받아 두 값을 비교하는 역할을 하는데, 이렇게만 설명하면 알기가 힘드니 자세하게 알아보도록 하겠습니다.
👉🏼 함수값에 대해 모르겠다면 여기를 참고해주세요.
함수값을 사용한다는 것은 내부에서 값을 전달받아 특정 로직을 실행할 수 있게 된다는 뜻입니다. 그리고 Comparator에 전달되는 함수값은 Comparator로부터 두 가지의 값을 전달받아 다시 Int 타입의 값을 반환하게 됩니다.
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fprod-files-secure.s3.us-west-2.amazonaws.com%252F83c75a39-3aba-4ba4-a792-7aefe4b07895%252F0e3f8b09-6893-4e20-8198-865a719a7900%252FUntitled.png%3Ftable%3Dblock%26id%3Df4550008-9d74-4689-8726-2e015cd77382%26cache%3Dv2&w=3840&q=75)
Comparator는 반환된 Int값을 기준으로 정렬을 진행하게 되는데, 전달되는 함수 블럭 내부에 로직을 작성해 원하는 정렬 조건을 설정할 수 있게 됩니다. 반환되는 값이 음수 (-)라면 o1 즉, 기존의 앞에 있던 원소가 앞에 위치하게 되고, 0이라면 기존의 순서, 양수 (+)라면 o2, 기존에 뒤에 있던 원소가 앞에 위치하게 됩니다.
뭔가 외워야 할 거 같고 어려워 보이지만 전달되는 값을 Int타입으로 생각하면 편합니다. 만약 두 값 3, 6이 주어졌다고 했을 때 앞에 위치한 값에서 뒤에 위치한 값을 뺀다면 어떤 값이 나올까요?
3이 앞에 있는 값 6이 뒤에 있는 값이라면 -3이, 순서가 반대라면 3이 나옵니다. 즉, 음수와 양수가 나오게 되는데, 이는 compare관련 함수들의 기본적인 동작 방식으로 주어진 두 값을 다음과 같은 방법으로 비교하게 됩니다. sortWith()는 Comparator를 전달받고, sortBy()는 내부적으로 Comparator를 사용하기 때문에 Comparator에 대해 알고 나면 이 같은 정렬 메서드들을 원활하게 사용할 수 있게 됩니다.
sortWith(), sortedWith()
sortWith()는 Comparator를 전달받아 정렬을 진행하게 됩니다. 즉 Comparator에 우리가 정의한 내용들이 정렬 기준이 되는 것이고 이에 따라 값들을 정렬하게 되는 것입니다.
array.sortWith( Comparator { o1, o2 -> if (o1.isLetter()) return@Comparator -1 if (o2.isLetter()) return@Comparator 1 return 0 )
위와 같이 값이 문자일 경우 순서를 앞쪽으로 보내는 기준을 만들 수 있습니다. 더 복잡한 기준도 만드는 것이 가능합니다. sortWith의 내부적으로는 Tim Sort 알고리즘이 사용된다고 합니다. 시간이 된다면 Tim Sort 알고리즘을 찾아보는 것도 좋습니다.
sortBy(), sortedBy()
sortBy() 메서드는 람다 함수를 인자로 전달받아 컬렉션의 특정 요소를 기준으로 정렬을 진행합니다.
data class Student(val name: String, val age: Int, val grade:Int, val class:Int) val sutudents = mutableListOf( Student("철수", 12, 5, 3), Student("영희", 13, 6, 1), Student("영수", 10, 3, 6) ) students.sortBy{ it.age } // 학생목록의 나이를 기준으로 정렬 students.sortBy{ it.age } // 학생 목록의 학년을 기준으로 정렬
위와 같이 객체의 프로퍼티가 다양할 때 특정 프로퍼티를 기준으로 정렬 조건을 설정하는 게 가능합니다. 또한 여러 가지 다중 조건을 설정하는 것도 가능한데요.
data class Student(val name: String, val age: Int, val grade:Int, val class:Int) val sutudents = mutableListOf( Student("철수", 12, 5, 3), Student("영희", 13, 6, 1), Student("영수", 10, 3, 6), Student("미진", 10, 3, 6) ) students.sortBy( { it.age }, { it.age }, { it.name} )
위처럼 여러 가지 기준을 사용해 정렬하는 게 가능합니다. 이때 순서는 가장 위쪽부터 하나씩 정렬 기준을 적용하며 조건을 비교했을 때 두 값이 일치하는 경우 다음 조건을 비교하는 방식으로 진행됩니다.
sortWith(), sortBy() 똑같은거 아니에요?
sortWith()와 sortBy()는 비슷해 보이지만 작동 방식이 전혀 다른 함수입니다. sortBy()의 경우, Comparator가 내부적으로 생성되기 때문에 정렬 대상을 각각 지정할 수 없어, 객체의 특정 프로퍼티를 기준으로 비교하는 방식에 사용하기 적절한 메서드라고 할 수 있습니다. sortWith()는 Comparator를 전달해야 하기 때문에 비교되는 두 값에 대해 각각 조건을 설정하는 게 가능해 보다 상세한 기준을 설정하는 게 가능합니다.
내일배움캠프는 개발에 필요한 핵심만 배웁니다
지금까지 꼭 필요한 개발 지식에 대해 알아보았습니다. 내일배움캠프에서는 전문가들이 선별한 핵심 개발 지식으로 개발 공부도, 취업도 보다 효율적으로 할 수 있는데요. 국내 유수의 IT기업 출신 튜터님들과 실습 위주의 독보적인 커리큘럼으로 개발자 취업을 체계적으로 준비해보세요. 내일배움캠프 4개월, 여러분 인생의 가장 큰 터닝 포인트입니다.
CREDIT
글 | 배영수 내일배움캠프 수료생
편집 | 정효재 팀스파르타 에디터
취업 준비, 어디서부터 시작해야 할지 모르겠다면?
🧐비전공자인데 IT 업계 취업할 수 있을까?
😟프로젝트 경험이 부족한데, 어떻게 준비해야 할까?
🥺IT 기업으로 이직하고 싶은데 뭐부터 시작해야 할까?
이런 고민을 하고 있다면, 내일배움캠프의 IT 취업 컨설팅을 받아보세요.
취업 코칭 전문가들이 여러분의 고민을 해결해 드립니다.
다음 링크에 이메일을 입력하시면 메일로 1:1 커리어 상담권과 취준 자료집을 보내드릴게요.
Share article
Subscribe to our newsletter