마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

코틀린 랜덤 문자열 생성

0 추천

숫자 + 소문자 영어 + 대문자 영어 가 섞인 20자리의 랜덤 문자열을 만들고 싶습니다.

 

var charPool : List<Char> = ('a'..'z') + ('A'..'Z') +('0'..'9')
val salt = ThreadLocalRandom.current().ints(20, 0, charPool.size).asSequence().map(
    charPool::get).joinToString("")

 

이 방식을 사용하면 되는걸 알긴 하지만 왜 이게 되는 것인지 잘 이해가 가지 않습니다.

저의 공부 부족인걸 알지만 설명 좀 부탁드립니다.

1.먼저 제가 모르겠는 부분은 ints(20, 0, charPool.size) 에서 20은 생성할 문자의 수, 0은 시작 부분인걸로 알겠는데 charPool.size를 넣어주는 이유는 뭔가요?

2.그 다음 asSequence는 정확히 무슨 역할을 하는 함수 인가요?

3.그 다음 map(charPool::get)이 있는데 제가 알고 있는 키 값 형태의 map은 아닌거 같은데 이 map은 어떤 함수이며, 매개변수의 역할은 뭔가요?

4. charPool::get은 정확히 뭘 의미하는 형태 인가요? :: 라는 부분 자체를 거의 본 적이 없어서;;;

 

5. 마지막으로 앞에 currenr()을 사용해 주는 이유는 현재의 스레드에서 작업한다는 의미일까요?

 

여기까지가 제가 모르는 부분 입니다. 따로 제가 직접 랜덤 난수 함수를 만들 수도 있지만 모르는건 공부하고 넘어가고 싶어서 질문 올립니다.

 

 

키리링 (840 포인트) 님이 2022년 6월 23일 질문

1개의 답변

0 추천
 
채택된 답변

ThreadLocalRandom에 대한 설명은 API문서를 찾아보시면 좋을 것 같습니다.
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadLocalRandom.html

Thread.current()대한 설명입니다.
Returns the current thread's ThreadLocalRandom.

 현재 쓰레드에 대한 ThreadLocalRandom을 리턴한다. 즉, 현재 쓰레드에서 실행되는 인스턴스를 리턴하는 걸로 보이네요.

 1. ints 메소드의 첫번째와 두번째 파라미터는 랜덤숫자를 생성하는 범위라고 보시면 됩니다. 예를들어 ints(20, 0, 10)이라고 하면 0부터 10사이의 정수(0 ~ 9)가 20개  생성되는 거죠.

2. Sequence는 Kotlin에서 Java의 stream처럼 빠른 연산을 위해 도입된 개념입니다. 이외에도 observable이 가능한 특성이 있기도 한데, 일단 collection을 사용할 때 성능향상을 위해 사용한다고 보시면 됩니다. 동작원리는 Kotlin 사이트에서 자세하게 읽어보세요.  https://kotlinlang.org/docs/sequences.html  페이지 중간 쯤에 다이어그램이 있을 겁니다. 그 부분을 보세요. 간략하게 요약하면  List.filter().map().filter()이런 식으로 Collection의 functional(함수형) 연산이 여러개 들어갈 때 일반적인 방식은 filter 의 결과를map연산을 하고 이 결과를 다시 filter를 하는 순차적 연산이라면 sequqnce를 사용하게 되면 첫번째 아이템에 대해 filter.map.filter를 처리하고 다음아이템으로 넘어갑니다. 이때 filter가 걸리지 않는 아이템은 map이 호출되지 않게 됩나다.

3. 맵의 함수 정의는 아래와 같습니다.

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

https://github.com/JetBrains/kotlin/blob/d8b0dbe71bbeb84ba0fbdac87801c8c6f4eed4c9/libraries/stdlib/common/src/generated/_Collections.kt#L1548

map은 extension function(확장함수?)로 List<T>의 루프를 돌면서 T타입인 아이템을 R타입으로 변환하여 List<R> 을 반환하는 겁니다. 잘 보시면 transform 파라미터는 함수타입니다. 파라미터로 함수타입을 넘기고자 할때 ::연산자를 사용해서 함수타입을 넘길 수 있습니다.

아래의 둘은 같습니다. 함수포인터를 사용하느냐 아느냐의 차입니다.

map(charPool::get)
map{ index -> charPool.get(index) } 

이걸 루프를 포함해서 작성하면, 아래와 같이 동작하게 됩니다.

val result = arrayListOf<Char>()
val indexes = ThreadLocalRandom().current.ints(20, 0, charPool.size)
for (index: Int in indexes) {
    result.add(charPool.get(index)) 
}

적절하게 쓰면 좋지만 남발하면 좋지 않습니다. map은 코틀린 뿐만 아니라 모던한 랭귀지라면 다들 지원하는 함수형 오퍼레이터입니다.

map은 콜렉션의 아이템을 바꾸는 함수 중의 하나입니다.  transformation 오퍼레이션은 자주 사용되고 다른 랭귀지에도 같은 기능들이 있으므로 잘 알아두시는게 좋습니다. filter, map, reduce정도는 잘 사용하실 수 있도록....

transformation에 대한 자세한 내용은 아래 링크를 읽어보세요.

https://kotlinlang.org/docs/collection-transformations.html

그리고 위의 코드를 코틀린의 extension function을 사용해서 다시 작성하면, 아래와 같이 할 수 있습니다.
 

val charPool = ...
charPool.shuffled().take(20)

// or
('a'..'z')
    .plus('A'..'Z')
    .plus('0'..'9')
    .shuffled()
    .take(20)

charPool을 섞어서 앞의 20개만 가져가는 코드입니다. 위의 예와 똑같이 동작할 겁니다. 역시나 간략해 보여서 좋긴하지만 너무 남발하면 곤란하겠죠.

spark (226,380 포인트) 님이 2022년 6월 23일 답변
키리링님이 2022년 7월 6일 채택됨
...