Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Meet the Swift Algorithms and Collections packages #12

Closed
yeongwoo-owo opened this issue Jun 21, 2022 · 0 comments
Closed

Meet the Swift Algorithms and Collections packages #12

yeongwoo-owo opened this issue Jun 21, 2022 · 0 comments
Assignees

Comments

@yeongwoo-owo
Copy link
Collaborator

Meet the Swift Algorithms and Collections packages

Sample Data

struct Member: Hashable {
    let name: String
    let imageName: String?
    let topics: [String]
}

let members = [
    Member(name: "호종이",
           imageName: "HoJongE.png",
           topics: ["Embrace Swift Generics",
                    "Add Rich Graphics to Your SwiftUI App"]),
    Member(name: "아보",
           imageName: nil,
           topics: ["Hello Swift Charts",
                    "Craft search experiences in SwiftUI"]),
    Member(name: "에이브리",
           imageName: "Avery.jpeg",
           topics: ["The SiwftUI cookbook for navigation"]),
    Member(name: "우디",
           imageName: nil,
           topics: ["Meet async/await in SwiftUI"]),
    Member(name: "에셔",
           imageName: "Asher.png",
           topics: ["What's New in Mapkit",
                    "Localize your SwiftUI App"]),
    Member(name: "찰리",
           imageName: "Charlie.jpeg",
           topics: ["ARC in Swift: Basics and Beyond"]),
    Member(name: "놔스닥",
           imageName: "Noasdaq.png",
           topics: ["Data Essentials in SwiftUI"]),
    Member(name: "포딩",
           imageName: nil,
           topics: ["Meet the Swift Algorithms and Collections"]),
    Member(name: "",
           imageName: "Taek.jpeg",
           topics: ["Stacks, Grids, and Outlines in SwiftUI"]),
    Member(name: "유스",
           imageName: "Youth.png",
           topics: ["Add intelligence to Your Widgets"])
]

Map

Returns an array containing the results of mapping the given closure over the sequence's elements.
Sequence의 Element를 Closure로 연산한 결과를 배열로 반환

Example

// Raw Loop
var namesByLoop: [String]  = []
for member in members {
    namesByLoop.append(member.name)
}

// Map
let namesByMap = members.map { $0.name }

print("namesByLoop: \(namesByLoop)")
print("namesByMap: \(namesByMap)")

// Result
// namesByLoop: ["호종이", "아보", "에이브리", "우디", "에셔", "찰리", "놔스닥", "포딩", "택", "유스"]
// namesByMap: ["호종이", "아보", "에이브리", "우디", "에셔", "찰리", "놔스닥", "포딩", "택", "유스"]

Map의 장점

  • 코드가 간단하다
  • 배열을 let으로 선언할 수 있다
  • 배열을 재할당하지 않아서 성능이 좋다

CompactMap

Returns an array containing the not-nil results of calling the given transformation with each element of this sequence.
Sequence의 Element를 Closure로 연산한 결과 중 nil이 아닌 값만 반환
Map + Optional Binding

Example

// Raw Loop + Optional Binding
var imagesByLoop: [String] = []
for member in members {
    if let image = member.imageName {
        imagesByLoop.append(image)
    }
}

// Map + Filter
let imagesByMap = members.filter{ $0.imageName != nil }.map{ $0.imageName! }

// CompactMap
let imagesByCompactMap = members.compactMap{ $0.imageName }

print("imagesByLoop: \(imagesByLoop)")
print("imagesByMap: \(imagesByMap)")
print("imagesByCompactMap: \(imagesByCompactMap)")

// Result
// imagesByLoop: ["HoJongE.png", "Avery.jpeg", "Asher.png", "Charlie.jpeg", "Noasdaq.png", "Taek.jpeg", "Youth.png"]
// imagesByMap: ["HoJongE.png", "Avery.jpeg", "Asher.png", "Charlie.jpeg", "Noasdaq.png", "Taek.jpeg", "Youth.png"]
// imagesByCompactMap: ["HoJongE.png", "Avery.jpeg", "Asher.png", "Charlie.jpeg", "Noasdaq.png", "Taek.jpeg", "Youth.png"]

FlatMap

Returns an array containing the concatenated results of calling the given transformation with each element of this sequence.
Sequence의 Element에 Closure를 연산한 결과를 배열로 반환, 2차원 배열일 경우 1차원으로 변환해서 반환
Map + Joined

Example

// Raw Loop
var topicsByLoop: [String] = []
for member in members {
    for topic in member.topics {
        topicsByLoop.append(topic)
    }
}

// Map
let topicsByMapOnly = members.map{ $0.topics }

// Map + Joined
let topicsByMap = Array(members.map{ $0.topics }.joined())

// FlatMap
let topicsByFlatMap = members.flatMap{ $0.topics }

print("topicsByLoop: \(topicsByLoop)")
print("topicsByMapOnly: \(topicsByMapOnly)")
print("topicsByMap: \(topicsByMap)")
print("topicsByFlatMap: \(topicsByFlatMap)")

// Result
// topicsByLoop: ["Embrace Swift Generics", "Add Rich Graphics to Your SwiftUI App", "Hello Swift Charts", "Craft search experiences in SwiftUI", "The SiwftUI cookbook for navigation", "Meet async/await in SwiftUI", "What\'s New in Mapkit", "Localize your SwiftUI App", "ARC in Swift: Basics and Beyond", "Data Essentials in SwiftUI", "Meet the Swift Algorithms and Collections", "Stacks, Grids, and Outlines in SwiftUI", "Add intelligence to Your Widgets"]
// topicsByMapOnly: [["Embrace Swift Generics", "Add Rich Graphics to Your SwiftUI App"], ["Hello Swift Charts", "Craft search experiences in SwiftUI"], ["The SiwftUI cookbook for navigation"], ["Meet async/await in SwiftUI"], ["What\'s New in Mapkit", "Localize your SwiftUI App"], ["ARC in Swift: Basics and Beyond"], ["Data Essentials in SwiftUI"], ["Meet the Swift Algorithms and Collections"], ["Stacks, Grids, and Outlines in SwiftUI"], ["Add intelligence to Your Widgets"]]
// topicsByMap: ["Embrace Swift Generics", "Add Rich Graphics to Your SwiftUI App", "Hello Swift Charts", "Craft search experiences in SwiftUI", "The SiwftUI cookbook for navigation", "Meet async/await in SwiftUI", "What\'s New in Mapkit", "Localize your SwiftUI App", "ARC in Swift: Basics and Beyond", "Data Essentials in SwiftUI", "Meet the Swift Algorithms and Collections", "Stacks, Grids, and Outlines in SwiftUI", "Add intelligence to Your Widgets"]
// topicsByFlatMap: ["Embrace Swift Generics", "Add Rich Graphics to Your SwiftUI App", "Hello Swift Charts", "Craft search experiences in SwiftUI", "The SiwftUI cookbook for navigation", "Meet async/await in SwiftUI", "What\'s New in Mapkit", "Localize your SwiftUI App", "ARC in Swift: Basics and Beyond", "Data Essentials in SwiftUI", "Meet the Swift Algorithms and Collections", "Stacks, Grids, and Outlines in SwiftUI", "Add intelligence to Your Widgets"]

Map, CompactMap, FlatMap, Filter 모두 반환 결과가 배열(Sequence), 따라서 반환 결과에 계속 이어서 사용할 수 있다.

let jpegImage = members.compactMap{ $0.imageName }.filter{ $0.hasSuffix(".jpeg") }
print("jpegImage: \(jpegImage)")

// Result
// jpegImage: ["Avery.jpeg", "Charlie.jpeg", "Taek.jpeg"]

이 경우 함수가 한번 실행될 때마다 새로운 배열이 생성되기 때문에 비효율적이다.
Lazy 알고리즘을 통해 이 문제점을 해결할 수 있다.

Lazy

A sequence containing the same elements as this sequence, but on which some operations, such as map and filter, are implemently lazily.
일반 시퀀스와 같은 element를 가지지만, map과 filter와 같은 연산을 할 때 lazily하게 처리
func getName(_ member: Member) -> String {
    print("getName \(member.name)")
    return member.name
}

let names = members.map{ getName($0) }

let namesLazy = members.lazy.map{ getName($0) }

print("\n--- No Lazy ---")
print("5번째 사람은 \(names[4]) 입니다")
print("\n--- Lazy ---")
print("5번째 사람은 \(namesLazy[4]) 입니다")

// Result
// getName 호종이
// getName 아보
// getName 에이브리
// getName 우디
// getName 에셔
// getName 찰리
// getName 놔스닥
// getName 포딩
// getName 택
// getName 유스

// --- No Lazy ---
// 5번째 사람은 에셔 입니다

// --- Lazy ---
// getName 에셔
// 5번째 사람은 에셔 입니다

Lazy를 이용하지 않는 map 함수의 경우, 모든 Element에 대한 연산을 모두 끝내서 배열을 만든 후, 5번째 원소에 접근하지만, Lazy를 이용한 map 함수는 5번째 원소에 접근할 때 5번째 원소에 대한 closure 연산을 하여 결과를 반환한다. 결과에 이용하지 않는 불필요한 연산 과정이 사라지기 때문에 효율적이다.

Swift Algorithms Package

Windows, AdjacentPairs, Chunks, Chunked 함수는 Algorithms Package를 다운 받아야 사용할 수 있다.
XCode의 File -> Add Packages -> Algorithms를 검색하여 패키지를 다운받을 수 있다.

Windows(ofCount: Int)

스크린샷 2022-06-21 오후 8 04 20

//  windows
let windowMember = Array(members.windows(ofCount: 3).map{ $0.map{ $0.name } })
print(windowMember)

// Result
// [["호종이", "아보", "에이브리"], ["아보", "에이브리", "우디"], ["에이브리", "우디", "에셔"], ["우디", "에셔", "찰리"], ["에셔", "찰리", "놔스닥"], ["찰리", "놔스닥", "포딩"], ["놔스닥", "포딩", "택"], ["포딩", "택", "유스"]]

AdjacentPairs

windows(ofCount: 2)와 유사하다.

//  adjacentPairs
let adjacentPairsMember = Array(members.adjacentPairs().map{ [$0.name, $1.name] })
print(adjacentPairsMember)

// Result
// [["호종이", "아보"], ["아보", "에이브리"], ["에이브리", "우디"], ["우디", "에셔"], ["에셔", "찰리"], ["찰리", "놔스닥"], ["놔스닥", "포딩"], ["포딩", "택"], ["택", "유스"]]

Chunks

스크린샷 2022-06-21 오후 8 11 44

//  chunks
let chunkedMember = members.chunks(ofCount: 3).map{ $0.map{ $0.name } }
print(chunkedMember)

// Result
// [["호종이", "아보", "에이브리"], ["우디", "에셔", "찰리"], ["놔스닥", "포딩", "택"], ["유스"]]

Chunks

스크린샷 2022-06-21 오후 8 11 59

//  chunked(on:)
let chunkedOnMember = members.chunked{ $0.name < $1.name }.map{ $0.map{ $0.name } }
print(chunkedOnMember)

// Result
// [["호종이"], ["아보", "에이브리", "우디"], ["에셔", "찰리"], ["놔스닥", "포딩"], ["택"], ["유스"]]

PDF

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant