Slide 1

Slide 1 text

HashableΛޡղͯ͠ ͍·ͨ͠ by. 2017/6/19 potatotips #41 1

Slide 2

Slide 2 text

takasek iOS Developer ϑϦʔϥϯε(΄΅FiNC) @takasek OSS ActionClosurable Notifwift౳ 2

Slide 3

Slide 3 text

struct YMD { let year: Int let month: Int let day: Int } ͜ΕΛ Set ʹೖΕ͍ͨ 3

Slide 4

Slide 4 text

4

Slide 5

Slide 5 text

public protocol Hashable : Equatable { public var hashValue: Int { get } } public protocol Equatable { public static func ==(lhs: Self, rhs: Self) -> Bool } 5

Slide 6

Slide 6 text

hashValue?! 6

Slide 7

Slide 7 text

7

Slide 8

Slide 8 text

A hash value, provided by a type’s hashValue property, is an integer that is the same for any two instances that compare equally. Πϯελϯεಉ࢜Λൺֱͯ͠equal ͳΒ ϋογϡ஋ʢ=hashValueʣ͸ಉ஋ 8

Slide 9

Slide 9 text

struct YMD: Hashable { let year: Int let month: Int let day: Int var hashValue: Int { // YYYYMMDD return year * 10000 + month * 100 + day } static func ==(lhs: YMD, rhs: YMD) -> Bool { return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day } } 9

Slide 10

Slide 10 text

hashValue ͱ == Ͱ ಉ͡Α͏ͳ͜ͱ ΍ͬͯΔͳʔ! 10

Slide 11

Slide 11 text

hashValue ʹ دͤͪΌ͑! 11

Slide 12

Slide 12 text

struct YMD: Hashable { let year: Int let month: Int let day: Int var hashValue: Int { // YYYYMMDD return year * 10000 + month * 100 + day } static func ==(lhs: YMD, rhs: YMD) -> Bool { return lhs.hashValue == rhs.hashValue } } 12

Slide 13

Slide 13 text

!ɹ 13

Slide 14

Slide 14 text

14

Slide 15

Slide 15 text

15

Slide 16

Slide 16 text

16

Slide 17

Slide 17 text

The reverse is not true: Two instances with equal hash values are not necessarily equal to each other. ! equal ͳΒ ϋογϡ஋͕ಉ஋ " ϋογϡ஋͕ಉ஋ ͳΒ equal 17

Slide 18

Slide 18 text

࣮ྫ 18

Slide 19

Slide 19 text

19

Slide 20

Slide 20 text

GridPoint ͸;ͨͭͷ஋ΛXORͯ͠hashValueΛٻΊ͍ͯΔ ݁Ռɺ x == y ͷͱ͖ৗʹhashValue͸0 20

Slide 21

Slide 21 text

21

Slide 22

Slide 22 text

ϋογϡ஋͸ িಥͯ͠΋ྑ͍ʂ 22

Slide 23

Slide 23 text

ͳͷͰɺ!͸Ϛζ͍ɻ static func ==(lhs: YMD, rhs: YMD) -> Bool { return lhs.hashValue == rhs.hashValue } ಉ͡ϋογϡ஋ͳΒequalͰ͋Δ͜ͱΛ ظ଴ͯ͠͠·͍ͬͯΔ࣮૷ͳͷͰɻ 23

Slide 24

Slide 24 text

ͦ΋ͦ΋ϋογϡ஋ͱ͸ ʮσʔλ֨ೲʹ͓͍ͯ ɹઢܗ୳ࡧͩͱ͕͔͔࣌ؒΔʯ ͱ͍͏໰୊Λղܾ͢ΔͨΊɺ ϋογϡςʔϒϧͰར༻͞ΕΔ஋ 24

Slide 25

Slide 25 text

ͲͷΑ͏ʹ σʔλ֨ೲͷ଎౓໰୊Λ ղܾ͢Δ͔ 1 1. nݸͷཁૉΛ࣋ͭ഑ྻʢ ϋ ογϡςʔϒϧ ʣΛ༻ҙ 2. ϋογϡ஋ % n ݸ໨ͷཁ ૉͱͯ͠σʔλΛ֨ೲ͢Δ 3. طଘͷσʔλ͕͋Δ৔߹ ͸ɺ୯ํ޲Ϧετͱͯ͠઀ ଓ͢Δʢ౳ͷํ๏ΛऔΔʣ 1 iOSΞϓϦʮΞϧΰϦζϜਤؑʯΑΓ 25

Slide 26

Slide 26 text

͡Ό͋ ద੾ͳhashValueͬͯ Ͳ͏࣮૷͢Ε͹ ͍͍ΜͩΖ͏! 26

Slide 27

Slide 27 text

ޮ཰ͷྑ͍ϋογ ϡ஋ͷ࡞Γํ ʢҰൠ࿦ʣ 4 ϋογϡ஋͸ɺͳΔ΂͘σʔλͷ֨ ೲઌͱͳΔ ϋογϡςʔϒϧͷཁૉ ͕͹Β͚ΔΑ͏ͳൣғΛऔΔͱྑ͍ 4 ϋογϡςʔϒϧͷཁૉ਺n ͷ஋ ͸ɺ଎౓ޮ཰ vs ϝϞϦޮ཰ ͷτϨ ʔυΦϑ 4 n͕େ͖͗͢ΔͱϝϞϦΛ৯͏ ʢ֬อͨ͠ྖҬ͕࢖ΘΕͳ͍ʣ 4 n͕খ͗͢͞Δͱ଎౓͕ग़ͳ͍ ʢিಥ͠ɺઢܗ୳ࡧ͕૿͑Δʣ 27

Slide 28

Slide 28 text

ޮ཰ͷྑ͍ϋογϡ஋ͷ࡞Γํ ʢSwift Standard Libraryͷ৔߹ʣ 4 ϋογϡςʔϒϧͷཁૉ਺n ͕Ͳ͏ܾఆ͞ΕΔͷ͔ɺ apple/swift ͷιʔεݟͯ΋௥͍͖Εͣ 4 ͨͩɺجຊ hashValue ͸ Int ͷൣғ಺Ͱ޷͖ͳ஋Λฦͤ ͹Α͠ͳʹ _squeezeHashValue ͯ͘͠ΕͯΔͬΆ͍ 4 ৄࡉͳϩδοΫ͸ཧղͯ͠ͳ͍͚Ͳɺ2ͷႈ৐Λ࢖ͬͯ hashValueͷিಥΛݮΒ͢ϩδοΫΒ͍͠ 4 cf. https://github.com/apple/swift/blob/master/ stdlib/public/core/Hashing.swift 28

Slide 29

Slide 29 text

ಡΜͰΘ͔Βͳ͍ͳΒ ܭଌͩ! code https://gist.github.com/takasek/ce66ac98f2971eac58991644d7471ccd 29

Slide 30

Slide 30 text

func YMDΛ10೥෼SetʹಥͬࠐΉ(using key: YMD.Key) { let cal = Calendar(identifier: .gregorian) // 2000/1/1 ͔Β 2010/12/31 ·Ͱͷ೔෇͕ॲཧର৅ let firstDate = DateComponents(calendar: cal, year: 2000, month: 1, day: 1).date! let lastDate = DateComponents(calendar: cal, year: 2010, month: 12, day: 31).date! var ymds: Set = [] var cursor = firstDate while cursor < lastDate { //Χʔιϧ͕ࣔ͢YMDΛSetʹೖΕΔ ymds.insert(YMD( year: cal.component(.year, from: cursor), month: cal.component(.month, from: cursor), day: cal.component(.day, from: cursor), keyForHashValue: key )) //ΧʔιϧΛҰ೔ਐΊΔ cursor = cal.date(byAdding: .day, value: 1, to: cursor)! } } 30

Slide 31

Slide 31 text

struct YMD: Hashable { let year: Int let month: Int let day: Int enum Key { case year, month, day, plusAll, xorAll, shiftAll, none } let keyForHashValue: Key var hashValue: Int { switch keyForHashValue { case .year: return year case .month: return month case .day: return day case .plusAll: return year * 10000 + month * 100 + day case .xorAll: return year ^ month ^ day case .shiftAll: return year << 14 + month << 5 + day //Ϗοτγϑτͯ͠ϢχʔΫʹ case .none: return 0 } } static func ==(lhs: YMD, rhs: YMD) -> Bool { return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day } } 31

Slide 32

Slide 32 text

֦େ! var hashValue: Int { switch keyForHashValue { case .year: return year case .month: return month case .day: return day case .plusAll: return year * 10000 + month * 100 + day case .xorAll: return year ^ month ^ day case .shiftAll: return year << 14 + month << 5 + day case .none: return 0 } } 32

Slide 33

Slide 33 text

ύϑΥʔϚϯεςετ݁Ռ ͸΍͞ ϋογϡ஋ 10೥෼SetʹಥͬࠐΉ࣌ؒ !1 YYYYMMDD 0.035 sec 2 Ϗοτγϑτ 0.037 sec 3 day 0.193 sec 4 Y ^ M ^ D 0.241 sec 5 month 0.335 sec 6 year 0.858 sec "7 ৗʹ0 2.656 sec 33

Slide 34

Slide 34 text

var hashValue: Int { // YYYYMMDD return year * 10000 + month * 100 + day } ૉ௚ͳ࣮૷Ͱѱ͘ͳ͍݁Ռ! 34

Slide 35

Slide 35 text

ޮ཰ͷྑ͍ϋογϡ஋ͷ࡞Γํɾ݁࿦(࢑ఆ) ʢSwift Standard Libraryͷ৔߹ʣ ܭࢉྔ͕ଟ͘ͳΒͳ͍ఔ౓ʹɺ IntͷൣғͰͳΔ΂͘ ϢχʔΫʹͳΔ஋Λฦͤ͹Αͦ͞͏ 35

Slide 36

Slide 36 text

·ͱΊ ਖ਼͍͠൑அ͕Ͱ͖ΔΑ͏ʹ ΞϧΰϦζϜΛֶ΅͏ʂ 36