forked from LoopKit/LoopKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCollectionType.swift
More file actions
73 lines (53 loc) · 1.87 KB
/
CollectionType.swift
File metadata and controls
73 lines (53 loc) · 1.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//
// CollectionType.swift
// Naterade
//
// Created by Nathan Racklyeft on 2/21/16.
// Copyright © 2016 Nathan Racklyeft. All rights reserved.
//
import Foundation
extension BidirectionalCollection where Index: Strideable, Element: Comparable, Index.Stride == Int {
/**
Returns the insertion index of a new value in a sorted collection
Based on some helpful responses found at [StackOverflow](http://stackoverflow.com/a/33674192)
- parameter value: The value to insert
- returns: The appropriate insertion index, between `startIndex` and `endIndex`
*/
func findInsertionIndex(for value: Element) -> Index {
var low = startIndex
var high = endIndex
while low != high {
let mid = low.advanced(by: low.distance(to: high) / 2)
if self[mid] < value {
low = mid.advanced(by: 1)
} else {
high = mid
}
}
return low
}
}
extension BidirectionalCollection where Index: Strideable, Element: Strideable, Index.Stride == Int {
/**
Returns the index of the closest element to a specified value in a sorted collection
- parameter value: The value to match
- returns: The index of the closest element, or nil if the collection is empty
*/
func findClosestElementIndex(matching value: Element) -> Index? {
let upperBound = findInsertionIndex(for: value)
if upperBound == startIndex {
if upperBound == endIndex {
return nil
}
return upperBound
}
let lowerBound = upperBound.advanced(by: -1)
if upperBound == endIndex {
return lowerBound
}
if value.distance(to: self[upperBound]) < self[lowerBound].distance(to: value) {
return upperBound
}
return lowerBound
}
}