You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: Boyer-Moore/README.markdown
+61-52
Original file line number
Diff line number
Diff line change
@@ -9,14 +9,14 @@ For example:
9
9
```swift
10
10
// Input:
11
11
let s ="Hello, World"
12
-
s.indexOf("World")
12
+
s.indexOf(pattern: "World")
13
13
14
14
// Output:
15
15
<String.Index?>7
16
16
17
17
// Input:
18
18
let animals ="🐶🐔🐷🐮🐱"
19
-
animals.indexOf("🐮")
19
+
animals.indexOf(pattern: "🐮")
20
20
21
21
// Output:
22
22
<String.Index?>6
@@ -32,7 +32,7 @@ Here's how you could write it in Swift:
32
32
33
33
```swift
34
34
extensionString {
35
-
funcindexOf(pattern: String) ->String.Index? {
35
+
funcindexOf(pattern: String) ->String.Index? {
36
36
// Cache the length of the search pattern because we're going to
37
37
// use it a few times and it's expensive to calculate.
38
38
let patternLength = pattern.characters.count
@@ -42,57 +42,58 @@ extension String {
42
42
// Make the skip table. This table determines how far we skip ahead
43
43
// when a character from the pattern is found.
44
44
var skipTable = [Character:Int]()
45
-
for (i, c) in pattern.characters.enumerate() {
46
-
skipTable[c] = patternLength - i -1
45
+
for (i, c) in pattern.characters.enumerated() {
46
+
skipTable[c] = patternLength - i -1
47
47
}
48
48
49
49
// This points at the last character in the pattern.
50
-
let p = pattern.endIndex.predecessor()
50
+
let p =index(before: pattern.endIndex)
51
51
let lastChar = pattern[p]
52
52
53
53
// The pattern is scanned right-to-left, so skip ahead in the string by
54
54
// the length of the pattern. (Minus 1 because startIndex already points
55
55
// at the first character in the source string.)
56
-
var i =self.startIndex.advancedBy(patternLength -1)
56
+
var i =index(self.startIndex, offsetBy: patternLength -1)
57
57
58
-
// This is a helper function that steps backwards through both strings
58
+
// This is a helper function that steps backwards through both strings
59
59
// until we find a character that doesn’t match, or until we’ve reached
60
60
// the beginning of the pattern.
61
61
funcbackwards() ->String.Index? {
62
-
var q = p
63
-
var j = i
64
-
while q > pattern.startIndex {
65
-
j =j.predecessor()
66
-
q =q.predecessor()
67
-
ifself[j] != pattern[q] { returnnil }
68
-
}
69
-
return j
62
+
var q = p
63
+
var j = i
64
+
while q > pattern.startIndex {
65
+
j =index(before: j)
66
+
q =index(before: q)
67
+
ifself[j] != pattern[q] { returnnil }
68
+
}
69
+
return j
70
70
}
71
71
72
72
// The main loop. Keep going until the end of the string is reached.
73
73
while i <self.endIndex {
74
-
let c =self[i]
75
-
76
-
// Does the current character match the last character from the pattern?
77
-
if c == lastChar {
78
-
79
-
// There is a possible match. Do a brute-force search backwards.
80
-
iflet k =backwards() { return k }
81
-
82
-
// If no match, we can only safely skip one character ahead.
83
-
i =i.successor()
84
-
} else {
85
-
// The characters are not equal, so skip ahead. The amount to skip is
86
-
// determined by the skip table. If the character is not present in the
87
-
// pattern, we can skip ahead by the full pattern length. However, if
88
-
// the character *is* present in the pattern, there may be a match up
89
-
// ahead and we can't skip as far.
90
-
i =i.advancedBy(skipTable[c] ?? patternLength)
91
-
}
74
+
let c =self[i]
75
+
76
+
// Does the current character match the last character from the pattern?
77
+
if c == lastChar {
78
+
79
+
// There is a possible match. Do a brute-force search backwards.
80
+
iflet k =backwards() { return k }
81
+
82
+
// If no match, we can only safely skip one character ahead.
83
+
i =index(after: i)
84
+
} else {
85
+
// The characters are not equal, so skip ahead. The amount to skip is
86
+
// determined by the skip table. If the character is not present in the
87
+
// pattern, we can skip ahead by the full pattern length. However, if
88
+
// the character *is* present in the pattern, there may be a match up
89
+
// ahead and we can't skip as far.
90
+
i =index(i, offsetBy: skipTable[c] ?? patternLength)
91
+
}
92
92
}
93
93
returnnil
94
-
}
94
+
}
95
95
}
96
+
96
97
```
97
98
98
99
The algorithm works as follows. You line up the search pattern with the source string and see what character from the string matches the *last* character of the search pattern:
@@ -149,34 +150,42 @@ Here's an implementation of the Boyer-Moore-Horspool algorithm:
// Google says it's 5857 km so our result is only off by 2km which could be due to all kinds of things, not sure how google calculates the distance or which latitude and longitude google uses to calculate the distance.
-`radius` is the radius of the sphere considered in meters, which defaults to the mean radius of the earth (from [WolframAlpha](http://www.wolframalpha.com/input/?i=earth+radius)).
16
+
17
+
The function contains 3 closures in order to make the code more readable and comparable to the Haversine formula given by the Wikipedia page mentioned above.
18
+
19
+
1.`haversine` implements the haversine, a trigonometric function.
20
+
2.`ahaversine` the inverse function of the haversine.
21
+
3.`dToR` a closure converting degrees to radians.
22
+
23
+
The result of `haversineDistance` is returned in meters.
24
+
25
+
*Written for Swift Algorithm Club by Jaap Wijnen.*
0 commit comments