TIL #44

loci·2024년 6월 13일
0

TIL

목록 보기
42/111


N개의 최소공배수

주어진 배열의 모든 수의 최소공배수를 구해야한다.

배열의 요소 두 수를 가져와 최소공배수와 최대공약수를 구하고 구해진 최소공배수를 다음 수와 계산해 최대공약수와 최소공배수를 마지막 요소까지 구해준다.
예전에 최소 공배수 문제가 나왔을때 공부했던 유클리드 호제법을 이용해 풀 수 있었다.


나의풀이

class Solution {
    fun solution(arr: IntArray): Int {
        var answer = arr[0]
        var tempGcd = 0
        for ( i in 1 until arr.size){
            tempGcd = gcd(answer, arr[i])
            answer = lcm(answer, arr[i], tempGcd)
        }
        return answer
    }
    
    tailrec fun gcd(a: Int, b: Int): Int {
        return if (b == 0) a else gcd(b, a % b)
    }
    
    fun lcm (a:Int, b: Int, gcd: Int) = a * b / gcd
}

다른사람의 풀이

class Solution {
    fun solution(arr: IntArray): Int {
        var answer = 1
        while(true) {
            var x = 0
            for(a in arr) x += answer%a
            if(x==0) return answer
            answer++
        }
        return answer
    }
}

코틀린 문법강의

유용한 기능

자료형 변환

  • 숫자 자료형끼리 to자료형() 메소드를 활용할 수 있음
  • 문자열을 숫자로 변경할때 별도의 메소드 필요

객체 자료형간의 변환

  • 객체 자료형간의 변환은 상속관계에서 가능

업캐스팅: 자식클래스 -> 부모클래스

var birds = mutableListOf<Bird>()
birds.add(Sparrow(name) as Bird)

Sparrow는 Bird의 자식클래스라 Bird로 형변환해 리스트에 넣을 수 있다.
as Bird부분은 생략이 가능하다.

다운캐스팅: 부모클래스 -> 자식클래스

var s1:Sparrow = birds.get(0) 

Sparrow는 Bird가 가져야할 정보를 모두 가지고 있지 않으면 오류가 난다.

자료형 타입확인

  • 코틀린은 is로 자료형의 타입을 확인할 수 있다.
	if(name is String) {
    	println("name은 String 타입입니다")
	} else {
    	println("name은 String 타입이 아닙니다")
	}

복수의 데이터 다루기

  • 메소드는 기본적으로 하나의 데이터를 리턴
  • 두개의 데이터는 데이터클래스를 설계하면 가능하지만 매번 불필요한 클래스를 만드는 것은 비효율적임

복수의 데이터 리턴방법

  • Pair를 사용해 두 개의 인스턴스 리턴
	var chicken = Chicken()
    var eggs = chicken.getEggs()
    var listEggs = eggs.toList()
    
    // first, second로 관리
    var firstEgg = eggs.first
    var secondEgg = eggs.second
    
    // 리스트로 관리
    var firstEgg = listEggs[0]
    var secondEgg = listEggs[1]
}

class Chicken {
    fun getEggs(): Pair<String, String> {
        var eggs = Pair("달걀", "맥반석")
        return eggs
    }
}
  • Triple을 사용해 세 개의 인스턴스 리턴
fun main() {
    var chicken = Chicken()
    var eggs = chicken.getThreeEggs()
    var listEggs = eggs.toList()
    
    // first, second, third로 관리
    var firstEgg = eggs.first
    var secondEgg = eggs.second
    var eggTime = eggs.third
    
    // 리스트로 관리
    var firstEgg = listEggs[0]
    var secondEgg = listEggs[1]
    var eggTime = listEggs[2]
}

class Chicken {
    fun getThreeEggs(): Triple<String, String, Int> {
        var eggs = Triple("달걀", "맥반석", 20230101)
        return eggs
    }
}

Scope Functions

let

  • 블록안 it으로 자신의 객체를 전달하고 수행 결과를 반환
var strNum = "10" 
var result = strNum?.let { // 중괄호 안에서는 it으로 활용함 Integer.parseInt(it) } println(result!!+1)

with

  • this로 자식의 객체를 전달하고 코드 수행결과 반환(this를 생략가능, null이 아닐때만 사용)
	var alphabets = "abcd"

with(alphabets) {
//      var result = this.subSequence(0,2)
    var result = subSequence(0,2)
    println(result)
}

also

  • it으로 자신의 객체를 전달하고 객체자신을 반환(apply와 함께 자주 사용)
var result = student?.also { it.age = 50 }
  • apply : this로 자신의 객체를 전달하고 객체자신을 반환 (주로 객체의 상태를 변화시키고 바로 저장할때 사용)
var result = student?.apply { student.age = 50 }

run

  • this로 접근하고 수행결과를 반환

객체에서 호출하지 않을 때

var totalPrice = run {
	var computer = 10000
	var mouse = 5000
	computer+mouse
}
println("총 가격은 ${totalPrice}입니다")

객체에서 호출할 때 : with와 달리 null체크를 할 수 있어 안전하게 사용가능

student?.run { displayInfo() }
Scope에서 접근방식 thisScope에서 접근방식 it
블록 수행 결과를 반환run, withlet
객체 자신을 반환applyalso

확장함수

  • 기존에 클래스에 쉽게 메소드를 추가할 수 있음
  • 외부에서 클래스의 메소드를 추가한다.
  • 외부에서 관리해 원본클래스의 일관성유지
    • 하위클래스에서 오버라이드 할수없음
    • public멤버에만 접근할 수 있음
fun String.isEmailValid(): Boolean {
    val pattern = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+"
    return matches(pattern.toRegex())
}

비동기 프로그래밍

  • 순서대로 하나의 작업씩 수행하는 행위를 동기적 프로그래밍이라고 함
  • 비동기 프로그래밍은 요청을 보내고 결과값을 받을 때까지 다른 작업을 수행하기 때문에 여러일을 한번에 수행

쓰레드

  • 쓰레드는 하나의 메인쓰레드(fun main())가 존재
  • thread키워드로 쓰레드를 생성해 동시에 로직을 실행할 수 있음

프로세스와 쓰레드
프로그램을 실행해 메모리에 올라가면 이를 프로세스라고 한다.
프로세스 안에 작업단위를 쓰레드라고 한다.
쓰레드는 각 독립된 메모리영역인 Stack을 가짐

코루틴 종속성추가

Kotlin/kotlinx.coroutines: Library support for Kotlin coroutines (github.com)

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC")
}
fun main() {
    thread(start = true) {
        for(i in 1..10) {
            println("Thread1: 현재 숫자는 ${i}")
            runBlocking {
                launch {
                    delay(1000)
                }
            }
        }
    }

    thread(start = true) {
        for(i in 50..60) {
            println("Thread2: 현재 숫자는 ${i}")
            runBlocking {
                launch {
                    delay(1000)
                }
            }
        }
    }
}

쓰레드를 동시에 시작해서 먼저 실행된 쓰레드의 숫자가 먼저 나오게됨

코루틴

  • 비동기 함수를 제공
  • 쓰레드 보다 가볍게 비동기 프로그래밍을 가능하게 해줌
  • 보통 launch async 를 많이 사용
  • launch는 결과값이 없는 코루틴 빌더이고 Job객체로 코루틴을 관리
  • async는 결과값이 있는 코루틴이고 Deffered타입으로 값을 리턴해줌
  • 코루틴을 실행할 쓰레드를 Dispatcher로 지정 (Dispatcher간 변환이 필요한 경우 withContext를 사용)

GlobalScope: 앱이 실행된 이유에 계속 수행되어야 할 때
CoroutineScope: 필요할때 생성 후 정리가 필요

Dispatchers.Main: UI와 상호작용하기 위한 메인쓰레드
Dispatchers.IO: 네트워크나 디스크 I/O작업에 최적화되어있는 쓰레드
Dispatchers.Default: 기본적으로 CPU최적화되어있는 쓰레드

쓰레드와 코루틴 정리

  • 쓰레드와 코루틴은 둘다 동시성 프로그래밍(비동기)을 위한 기술
  • 동시성 프로그래밍 기술은 컨텍스트 스위칭이 중요한 개념

쓰레드

  • 작업 하나하나의 단위 - Thread
  • 각 Thread가 독립적인 Stack메모리 영역을 가짐
  • 동시성 보장수단 : 운영체제 커널에 의한 context switching

블로킹 (Blocking)
Thread AThread B 결과를 기다릴때 Thread A는 Blocking상태이고 Thread B의 결과가 나올때까지 해당 자원을 사용하지 못함

코루틴

  • 작업 각각에 Object(Coroutine Object)를 할당
  • Coroutine Object도 객체기 때문에 JVM Heap에 적재
  • 동시성 보장수단 : Programmer Switching(NO-Context Switching)
  • 소스코드를 통해 Switching시점을 마음대로 정함
  • 코루틴을 Light-Weight Thread라고 이야기함
    동시처리를 위해 스택영역을 별도로 할당하는 쓰레드처럼 동작하지 않고 동시성을 보장할 수 있으며 하나의 쓰레드에서 다수의 코루틴을 수행하고 커널의 스케쥴링을 따르는 컨텍스트 스위칭을 수행하지 않음

Suspend(Non-Blocking)
Thread A가 Object1을 실행하다가 Object2의 결과를 기다릴 때 Object1은 suspend로 바뀌고 Thread A는 멈추지 않고 다른작업을 수행하다가 Object1이 결과를 다시 받으면 Thread A가 다시 Object1을 수행한다.

profile
편리한 개발자

0개의 댓글