티스토리 뷰

반응형

으아아아ㅏ아앙아아ㅏ아아아아!!!!!!!!!!!!!!!!!!!!!!!

이제 알겠습니다.

ㅎ아ㅏ하흐아하ㅏ아아ㅏ 넘좋아

제가 이때까지 코딩을 어떻게 했냐면요


 var read = readLine()


    if var read = read{

        var arr =  read.components(separatedBy: ",")

        print(Int(arr[0])! + Int(arr[1])!) //끔찍한 부분

}

옵셔널 바인딩까지는 이해하겠습니다.

하지만 readLine이 String? 타입인 관계로 Int로 처리하려면 항상!!! 항상 Convert를 해주었어요.

솔직히 저 코드가 존재함으로써 뭔가 더러워보이지 않나요?

제 코드의 미의 기준에 상당히 어긋나는 코드였는데, 스택오버플로우를 가봐도 다 이렇게 Convert를 하더라구요

그래서 Swift라는 언어에 실망을 가지려는 찰나

발견했습니다. 하하하핳ㅎ하하하

아 너무 좋네요. 

근데.. 기대하진마세요.....

⭐️map⭐️이라는 swift의 고차함수를 쓰니까요...

그래도 저는 한줄에 String을 Int로 바꿀 수 있다는 점이 너무 기뻐요 ㅠㅠㅠㅠㅠ

하하핳ㅎㅎ넘 조아





map



이제 알려드리겠습니다. 

혹시 swift의 고차함수인 map을 아시나요? 

간단하게 설명드리자면, 

map 메소드는 제공된 클로저를 각 행렬 항목마다 적용한 후, 새롭게 매핑된 값들이 원래 행렬의 해당 값들의 순서와 같도록 배치된 새 행렬을 반환합니다.

 map은 mapping에서 나온거랍니다 ㅎㅎ


[x1, x2, ... xn].map(f) -> [f(x1), f(x2), ... , f(xn)]

어떤 배열에 f라는 기준(클로저)으로 map을 해주니까 원래 배열의 모든 요소가 f라는 기준이 적용된 요소가 되었죠?

이것을 가능하게 해주는 것이 map입니다. 


그럼 map을 어떻게 쓰는지 알아봅시다. 일단 함수를 쓰려면 그 함수의 원형을 보는게 가장 먼저겠죠?


Array.map(transform: T -> U)


transform 으로 넘기는 것은 클로져(Closure)인데 T는 원래 Array의 타입이고 U는 새롭게 만들 Array의 아이템 타입이라고 하네요.

여기서 제가 설정한 기준으로 새로운 Array를 만들게 되는거죠. 

꼭 Array만 만들어지는 것은 아니에요!



예제를 통해 살펴볼까요?

우리가 궁극적으로 원하는 String에서 Int로 고치는 예제를 한번 같이 해봐요.


 var read = readLine()


    if var read = read{

        var arr =  read.components(separatedBy: " ").map({ (value : String) -> Int in return Int(value)! })

}


아...너무 ....길어서....스크롤..해야..보이네요..캡쳐를 해보겠습니다. 



일단 map은 받은 배열의 모든 원소를 봅니다.


일단 우리가 주는 (위에서 T타입인) 타입은 String이죠?

 String을 Int로 고쳐야 하니까요. 그러니까 ->는 리턴을 의미합니다. 

-> 뒤에 Int가 적혀있네요?


그럼 (value : String) -> Int이라는 말은 

String으로 배열을 받는데, Int형 배열로 반환해주겠다..라는 소리겠네요. 


근데 이렇게만 하면 map이 아니겠죠? 어떤 '기준'을 설정해줘야해요. 

모든 요소는 이 기준에 따라 바뀌게 되겠죠.



in return은 '어 리턴해주긴 하는데 이 뒤에 있는 거 적용시켜서 리턴해주라' 이소리에요.

그렇다면 in return Int(value)!이라는 소리는 

"어 이 기준에 따라서 배열 하나 리턴해주라." 라는 겁니다.



근데 우리가 리턴할 타입은 Int죠? 그러니까 각 요소를 Int로 Convert해주어야 하는겁니다. 

실제로 저 Int로 바꿔주지 않게 되면, 그러니까



이렇게 해주면, 



String타입을 변환할 수 없다고 그러죠? 클로져의 결과타입인 Int로요.


ㅎㅎ자 그럼 정상적인 코드로 돌아가서, 실행시켜보면 





짠 이렇게 잘 나오게 된답니다. map은 배열을 리턴해주니, 배열형태로 나오게 되었죠?ㅎㅎ

이렇게 한번에 String을 주어진 separator로 나눠주고, 매핑까지 한번에 할 수 있게 되었어요. 

특정한 값만 얻어오고 싶으면 arr[인덱스]를 해주면 되겠죠?





근데.... 전 세계 사람들은 다들 똑같은 마음이었다는 겁니다,

map이 쓰기 짱어렵게 생겼따는 사실

언제 저거 적고있어 ㅡㅡ






이래서 애플은 map을 축약하고 또 축약할 수 있도록 만들어주었습니다!!!!

Xcode가 짱 똑똑해서 추론을 잘하거든요. 이 Xcode가 축약을 가능하게 해준답니다.


● 축약 - 1


일단 우리가 String타입의 배열을 넘겨주죠?

하지만 Xcode도 압니다. 보면 readLine은 String이니까..그래서 타입을 꼭 적어주지 않아도 됩니다.

var arr = read.components(separatedBy: " ").map({ (value) -> Int in return Int(value)! })

오 드디어 이제 한눈에 볼 수 있게 되었군요 ㅎㅎ작아졌지만...

저 value뒤에 String이라는 키워드가 없어진 것. 보이시나요?





● 축약 - 2



자 여기서 또 축약 해봅시다.

바로 in return 인데요, Xcode는 짱 똑똑해서 압니다. 이 뒤에는 조건이 들어간다는것을...

조건이 만약 한줄이라면,(두 줄 이상일때는 return을 써줘야합니다.)

그래서 in return대신에 in만 써주어도 '아 이뒤에는 조건이 나올 건가봐!!'하고 알 수 있답니다.

그래서

var arr =  read.components(separatedBy: " ").map({ (value) -> Int in Int(value)! })

in뒤에 return이 사라진 것 보이시나요?ㅎㅎ

자 이게 끝이냐

아닙니다. 오늘 축약의 끝을 보실 수 있을 겁니다....




● 축약 - 3


자, 또 축약을 한번 더 해보자면

in 뒤에서 우리는 Int로 Convert를 해주게 되는데, ㄷ또 우리 짱 똑똑한 Xcode는 아는거죠..

아 내가 반환할 배열은 Int형 타입이겠구나...

그럼 이제 좀 추측이 가시나요? 


var arr =  read.components(separatedBy: " ").map({ (value) in Int(value)! })

!!! 두둥 -> 라는 기호와 Int가 없어졌네요. -> Int자체가 Int타입을 리턴할거야! 라는 것이니

둘다 없어도 되는거겠죠.

자.. 정말 많이 줄어들었죠? ㅎㅎㅎ 여기서 더 축약을 할 수 있다면 믿으시겠어요?  ㄷㄷ

자 일단 중복이 보입니다. 네. value요 아니 누가 두번 쓰고 싶겠어요 ㅎㅎ


앗 그럼 


var arr =  read.components(separatedBy: " ").map({ Int(value)! })

이렇게 줄일 수 있는건가요?????!! 하실 수도 있지만, 음 아닙니다. 위 코드는 오류를 내게 될텐데요, 

일단 value라는 것을 정의하지 않았으니 이 value가 뭔지 모르는겁니다.



● 축약 - 4


그래서 우리 애플은 극단적으로 $0이라는 기호를 사용하게 됩니다.

$0은 그냥 value를 기호로 나타낸 것 뿐, 똑같은 기능을 합니다.


var arr =  read.components(separatedBy: " ").map({ Int($0)! })



짠~~ㅎㅎㅎ어때요 ㄷㄷ 또 여기서 더 축약이 가능하다고 하시면 믿으실건가요?ㅎㅎㅎㅎ


● 축약 - 5


var arr =  read.components(separatedBy: " ").map() { Int($0)! }

저렇게 클로저를 감싼 ()를 앞으로 가져올 수 있답니다.

한번 더 축약이 가능하다고 하면 믿으실건가요 ㄷㄷ?




● 축약 - 6


var arr =  read.components(separatedBy: " ").map{ Int($0)! }

가능은 한데요, 저 ()를 없앨 수 있습니다. ㄷㄷ 이정도면 축약의 끝판왕 아닌가요?

자, 실행해보면 


짠~~~ㅎㅎㅎ


자..그런데 map은 치명적인 단점을 가지고 있는데요, 뭘 것 같으세요?

네... 누군가 제 코드를 봤을 때 이게 뭔소린지 모른다는 겁니다...................

그래서 극단적으로 저렇게 축약의 축약은 자제하시는 것이 좋아요. 특히 Swift를 이제 갓 배우시는 분들에게는 비추드립니다(저한테 하는말)

스택오버플로우 가보시면 $0이 난무하는 것을 볼 수 있는데요, 이 축약된 클로져의 원래형태가 어떤것이였는지 연습하는 것이 좋아요 :) 야곰님이 해주신 말씀이랍니다.


저는 일단 하나도 축약하지 않고 써볼려구요 ㅎㅎㅎㅎ

그렇게 연습하면서 차차 축약을 해나가는거죠 흫ㅎ




 var read = readLine()


    if var read = read{

        var arr =  read.components(separatedBy: ",")

        print(Int(arr[0])! + Int(arr[1])!) //끔찍한 부분

}

이 코드가

var read = readLine()!

var arr = read.components(separatedBy: " ").map({ (value : String) -> Int in return Int(value)! })

print(arr[0]+arr[1])

이렇게 바뀔 수 있겠네요 ㅎㅎ

readLine을 강제로 받아오면 옵셔널 바인딩을 하면 안된답니다. ㅎㅎ 더 깔끔해져서 이렇게 해봤어요.



아무튼 오늘의 주제는 String을 Int로 한줄로 변환하는 방법에 대해서 쓸려고 시작한건데.. map의 개념까지 쓰게 됐네요 XD 


도움이 되었으면 좋겠어요 😆


반응형