Skip to content

Instantly share code, notes, and snippets.

@joanromano
Created September 8, 2019 10:15
Show Gist options
  • Save joanromano/ca3bc5b0cce05849857b11de59f80a1b to your computer and use it in GitHub Desktop.
Save joanromano/ca3bc5b0cce05849857b11de59f80a1b to your computer and use it in GitHub Desktop.
A basic trie implementation in Swift supporting prefix and pattern searches
class TrieNode {
var hash: [Character:TrieNode] = [:]
var endOfWord: Bool = false
}
class Trie {
var root = TrieNode()
init() {}
func insert(_ word: String) {
var current = root
for character in word {
if let next = current.hash[character] {
current = next
} else {
current.hash[character] = TrieNode()
current = current.hash[character]!
}
}
current.endOfWord = true
}
func matchPrefix(_ prefix: String) -> [String] {
var current = root
for character in prefix {
if let next = current.hash[character] {
current = next
} else {
return []
}
}
var result = [String]()
_matchPrefix(current, prefix, &result)
return result
}
func _matchPrefix(_ node: TrieNode, _ path: String, _ result: inout [String]) {
if node.endOfWord {
result.append(path)
}
for (character, node) in node.hash {
_matchPrefix(node, path + [character], &result)
}
}
func matchPattern(_ pattern: String) -> [String] {
var result = [String]()
_matchPattern(root, pattern, &result, "", 0)
return result
}
func _matchPattern(_ node: TrieNode, _ pattern: String, _ result: inout [String], _ path: String, _ i: Int) {
if i == pattern.count {
if node.endOfWord {
result.append(path)
}
return
}
let nextCharacter = Array(pattern)[i]
if nextCharacter == "." {
for (nextCharacter, child) in node.hash {
_matchPattern(child, pattern, &result, path + [nextCharacter], i+1)
}
} else if nextCharacter == "*" {
// Don't consume
_matchPattern(node, pattern, &result, path, i+1)
// Consume
for (nextCharacter, child) in node.hash {
_matchPattern(child, pattern, &result, path + [nextCharacter], i)
}
} else if nextCharacter == "?" {
// Don't consume
_matchPattern(node, pattern, &result, path, i+1)
// Consume
for (nextCharacter, child) in node.hash {
_matchPattern(child, pattern, &result, path + [nextCharacter], i+1)
}
} else if i+1 < pattern.count, Array(pattern)[i+1] == "/" {
// Don't consume
_matchPattern(node, pattern, &result, path, i+2)
// Consume
if let child = node.hash[nextCharacter] {
_matchPattern(child, pattern, &result, path + [nextCharacter], i)
}
} else {
if let child = node.hash[nextCharacter] {
_matchPattern(child, pattern, &result, path + [nextCharacter], i+1)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment