Slide 1

Slide 1 text

COLLECTION操作の罠 Navigate : Space / Arrow Keys | - Menu | - Fullscreen | - Overview | - Blackout | - Speaker | - Help M F O B S ?  1 / 28

Slide 2

Slide 2 text

Profile Takuhiro Muta iOS Enginner@iRidge inc. Twitter/Qiita: @417_72ki GitHub: 417-72KI [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  2 / 28

Slide 3

Slide 3 text

本題 [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  3 / 28

Slide 4

Slide 4 text

Objective-CからSwift JavaからKotlin(またはJava8) になるに従って コレクション操作が大幅に楽になりました [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  4 / 28

Slide 5

Slide 5 text

昔 Objective-C Java(~7) NSArray *array = ... NSArray *evenArray = [NSMutableArray new]; for (NSNumber *num in array) { if(num.integerValue % 2 == 0) { [evenArray addObject:num]; } } List list = ... List evenList = new ArrayList<>(); for(int num: list) { if(num % 2 == 0) { evenList.add(num); } } [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  5 / 28

Slide 6

Slide 6 text

今 Swift Kotlin let list = [1,2,3,4,...] let evenList = list.filter { $0 % 2 == 0 } val array = arrayOf(1,2,3,4,...) val evenList = array.filter { it % 2 == 0 }.toTypedArray() [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  6 / 28

Slide 7

Slide 7 text

ちょっと複雑な例 [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  7 / 28

Slide 8

Slide 8 text

let range = 1...10 let newList = range.filter { $0 % 2 == 0 } .map { $0 / 2 } .map { $0 * 5 } .filter { $0 > 10 } [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  8 / 28

Slide 9

Slide 9 text

map と filter の定義 public func map(_ transform: (Element) throws -> T) rethrows -> public func filter(_ isIncluded: (Element) throws -> Bool) rethrow [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  9 / 28

Slide 10

Slide 10 text

どちらも配列を返している... [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  10 / 28

Slide 11

Slide 11 text

分かりやすいように画面出力してみましょう func multiply(_ i: Int) -> (Int) -> Int { return { print($0, "*" , i, "=", $0 * i) return $0 * i } } func divide(_ i: Int) -> (Int) -> Int { return { print($0, "/" , i, "=", $0 / i) return $0 / i } } func isOdd() -> (Int) -> Bool { return { print($0, "odd?" , $0 % 2 == 0) return $0 % 2 == 0 [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  11 / 28

Slide 12

Slide 12 text

実行結果 1 odd? false 2 odd? true 3 odd? false 4 odd? true 5 odd? false 6 odd? true 7 odd? false 8 odd? true 9 odd? false 10 odd? true 2 / 2 = 1 4 / 2 = 2 6 / 2 = 3 8 / 2 = 4 10 / 2 = 5 1 * 5 = 5 [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  12 / 28

Slide 13

Slide 13 text

イメージ List l = new ArrayList<>(); for (int n: array) if (isOdd(n)) l.add(n); List l2 = new ArrayList<>(); for (int n: l) l2.add(divide(n, 2)); List l3 = new ArrayList<>(); for (int n: l2) l3.add(multiply(n, 5)); List result = new ArrayList<>(); for (int n: l3) if (isMoreThan(n, 10)) result.add(n); [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  13 / 28

Slide 14

Slide 14 text

ループ回しすぎぃ! [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  14 / 28

Slide 15

Slide 15 text

これが要素数100万とかの配列になったら... [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  15 / 28

Slide 16

Slide 16 text

((((;゚Д゚)))) [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  16 / 28

Slide 17

Slide 17 text

そこで [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  17 / 28

Slide 18

Slide 18 text

Swift → LazyCollection Kotlin → Sequence [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  18 / 28

Slide 19

Slide 19 text

どちらも遅延評価で実行してくれる [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  19 / 28

Slide 20

Slide 20 text

さっきの例 これを var list = 1...10 let newList = list.filter(isOdd()) .map(divide(2)) .map(multiply(5)) .filter(isMoreThan(10)) [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  20 / 28

Slide 21

Slide 21 text

こうじゃ var list = 1...10 let newList = list.lazy .filter(isOdd()) .map(divide(2)) .map(multiply(5)) .filter(isMoreThan(10)) .reduce(into: [Int] ()) { (array: inout [Int], i: Int) in arr [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  21 / 28

Slide 22

Slide 22 text

実行結果 1 odd? false 2 odd? true 2 / 2 = 1 1 * 5 = 5 5 > 10 : false 3 odd? false 4 odd? true 4 / 2 = 2 2 * 5 = 10 10 > 10 : false 5 odd? false 6 odd? true 6 / 2 = 3 3 * 5 = 15 15 > 10 : true 7 odd? false [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  22 / 28

Slide 23

Slide 23 text

イメージ 1ループで回す感じに List result = new ArrayList<>(); for (int n: array) { if (!isOdd(n)) continue; int n2 = divide(n, 2); int n3 = multiply(n2, 5) if (isMoreThan(n3, 10)) result.add(n3); } [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  23 / 28

Slide 24

Slide 24 text

ちなみにKotlinの場合は array.asSequence() をmapとかfilterとかの前に 呼ぶだけ [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  24 / 28

Slide 25

Slide 25 text

どういう時に有効? 大きいデータから複数の条件に合致する数件だけを 抽出する [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  25 / 28

Slide 26

Slide 26 text

Before 実行時間: 0.7900744676589966 let range = 1...1000 let result1 = range .filter(isOdd()) .map(divide(2)) .map(multiply(5)) .filter(isMoreThan(10)) .prefix(5) [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  26 / 28

Slide 27

Slide 27 text

After 実行時間: 0.00704646110534668 let range = 1...1000 let result2 = range.lazy .filter(isOdd()) .map(divide(2)) .map(multiply(5)) .filter(isMoreThan(10)) .prefix(5) .reduce(into: [Int] ()) { (array: inout [Int], i: Int) in arr [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  27 / 28

Slide 28

Slide 28 text

まとめ 膨大なコレクションを操作する際は遅延評価の検討 を! [ GitPitch @ github/417-72KI/Slides4LT/trap-of-collections ]  28 / 28