비밀 악수 - 10진수와 2진수
2진수에 관해서는 당신은 비밀스런 "악수"를 내놓기로 결정했습니다.
1 = wink
10 = double blink
100 = close your eyes
1000 = jump
10000 = Reverse the order of the operations in the secret handshake.
십진수가 주어지면 비밀 핸드 쉐이크를위한 적절한 이벤트 시퀀스로 변환합니다.
다음은 몇 가지 예입니다.
입력 3이 주어지면,이 함수는 3이 11 진법이므로 배열 [ "wink", "double blink"]을 반환합니다.
주어진 입력 값 19가 주어지면이 함수는 배열 [ "double blink", "wink"]을 반환 할 것입니다. 19가 이진수로 10011이기 때문입니다. 16 (이진수로 10000)을 추가하면 배열이 반전됩니다.
해결안1) 재귀 함수
listOf()
1) 먼저 들어온 인수 n에 대하여 16이상인지 확인합니다 .
2) 만약 16이상이라면 들어온 인수에대하여 -16을 하고 다시 자기자신을 호출합니다. 그리고 리턴값(리스트)을 거꾸로 뒤집습니다 .
3) 그리고 다시 호출된 재귀함수 자기자신에서 그다음 else if문으로 들어가서 조건에 맞다면 리스트에 값을 추가하고 자기자신을 다시 호출하는 식으로 반복합니다 .
4) 최종 결과값은 리스트로 리턴합니다 .
해결안 2) 중위함수 ,비트 시프트(shr) ,비트연산 and , apply
}
1) 먼저 중위함수를 선언합니다 . 중위함수는 infix 키워드를 fun 앞에 붙여 만들수 있습니다 .
number hasBitSet 0 처럼 확장함수를 중간에 사용할 수 있습니다.
2) 그리고 shr 연산자를 이용하여 중위연산자 왼쪽의 int 값을 오른쪽으로 매개변수 bit 만큼 비트연산합니다 (1/2) 계산
3) 위의 시프트 한 값을 다시 1과 and 연산하여 그 값을 정수 1과 비교합니다 .
4) calculatorHandshake 함수로 돌아가서 mutableListOf 함수로 리스트를 생성하고 , apply() 함수를 통하여
자기자신을 인자로 받고 , 자기자신을 리턴하게 됩니다 .
5) apply 함수 안에서 위에서 선언했던 중위 확장함수를 이용하여 그값이 true 라면 mutableList에 값을 추가합니다 .
6) hasBitSet은 총 5번 호출되며, 마지막 number hasBitSet 4 가 트루라면 리스트를 거꾸로 뒤집습니다 .
Infix
infix
키워드를 사용해서 중위(Infix) 표현으로 사용할 수 도 있습니다.
fun Int.multiply(x: Int): Int {
return this * x
}
위의 코드는 Int를 확장한 확장 함수이다. 간단하게 생각하면 Int 클래스의 함수를 더 추가 한다고 생각하면 됩니다.
val multiply = 3.multiply(10)
그럼 위와 같이 확장함수를 이용해서 간단하게 만든 multiply 를 사용할 수 있다. 중위 표현으로 변경하면 다음과 같습니다.
infix fun Int.multiply(x: Int): Int {
return this * x
}
위와 같이 infix
키워드를 사용하면 중위 표현을 사용할 수 있습니다 .
val multiply = 3 multiply 10
해결안 3) 2진 표현법 (0b) , map, let, 확장함수
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private val handshakeCodes = mapOf( 0b0001 to Signal.WINK, 0b0010 to Signal.DOUBLE_BLINK, 0b0100 to Signal.CLOSE_YOUR_EYES, 0b1000 to Signal.JUMP ) private val REVERSE = 0b10000 fun calculateHandshake(flags: Int) = handshakeCodes .map { if (flags.hasFlag(it.key)) it.value else null } .filterNotNull() .let { if (flags.hasFlag(REVERSE)) it.asReversed() else it } private fun Int.hasFlag(flag: Int) = // this and flag != 0 and(flag) != 0 | cs |
1)변수 handshakeCodes에 맵을 생성합니다. key는 2진수값, value는 enum값을 넣어줍니다 .
2) calculateHandshake 함수에서 위의 변수를 map{} 으로 변환합니다 .
3) map{} 안에서는 handshakeCodes 변수의 맵의 각 인덱스 값을 가져와 if문으로 확인합니다.
4) if 문 안에서는 확장함수 hasFlag 를 호출하며 ,hasFlag 함수는 확장함수로 , Int 값과 매개변수로 받은 값을 and연산하고, 그값이 0과 다르다면 true를 리턴합니다 .
5) 만약 calculateHandshake 함수에 4가 들어왔다면 맵의 키 0b0100과 같을때만 맵의 value값을 가져와 리스트에 추가합니다 . map{}의 반환형은 List 입니다 .
map
지정된 변환 함수를 원의 char 순서의 각 문자에 적용한 결과를 포함한리스트를 돌려줍니다 .
fun <R> CharSequence.map(transform: (Char) -> R): List<R>
6) list에서 null이 아닌값만 필터하고 리턴값은 List입니다 .
filterNotNull
fun <T : Any> Array<out T?>.filterNotNull(): List<T>
7) let함수를 통하여 자기자신을 인자로 넘겨서 if문을 실행합니다 .
8) if 문에서는 calculateHandshake로 넘겨받은 값이 16이라면 리스트를 뒤집습니다 .
해결안 4) enum.values(), ordinal,
}
1) calcultateHandshake 함수에서 EnumClass Signal의 values함수를 호출합니다 .
EnumClass.valueOf(value: String): EnumClass
EnumClass.values(): Array<EnumClass>
을 통하여 Enum클래스의 상수에 접근할 수있습니다 .
2) EnumClass.values()로 얻은 어레이리스트를 filter 하는데
3) isBitSet 이라는 확장함수가 true인것만 필터합니다 .
4) isBitSet 함수의 매개변수로 첫번째로 ordinal을 받는데 , ordinal은 Enum의 선언 위치입니다 .(Int)
ordinal
val ordinal: Int
이 열거 정수의 서수 (열거 형 선언의 위치, 초기 상수에 0의 서수가 할당 됨)를 리턴합니다.
두번째 매개변수로는 calculateHandshake의 매개변수로 받은 Int 값을 전달합니다 .
5) isBitset 함수 내에서는 calculateHandshake의 매개변수를 Enum의 ordinal만큼 시프트 라이트 하여 ,
1과 비교하여 같다면 true를 리턴합니다
6)결과적으로 result에는 Enum에서 필터링된 값들의 리스트가 남게되고 , 마지막으로 Reverse 인지를 체크하여 리스트를 리턴합니다 .
'Kotlin > Exercise' 카테고리의 다른 글
완벽한 숫자 - 자연수에대한 (2) | 2019.03.27 |
---|---|
정사각형의 차이 (4) | 2019.03.17 |
스크래블 스코어 - 주어진 단어에대하여 점수 계산하기 (4) | 2019.03.17 |
어구를 약어로 변경하기 (2) | 2019.03.14 |
스트링 뒤집기 (2) | 2019.03.13 |
댓글