Skip to content

Instantly share code, notes, and snippets.

@ygrenzinger
Created May 13, 2020 14:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ygrenzinger/ef2b4dd27b022fbe7f6ab9c3a9e848ee to your computer and use it in GitHub Desktop.
Save ygrenzinger/ef2b4dd27b022fbe7f6ab9c3a9e848ee to your computer and use it in GitHub Desktop.
Jetbrains academy SimpleSearchEngine
package search
import java.io.File
import java.util.*
typealias InvertedSearchData = MutableMap<String, Set<Int>>
enum class MatchingStrategy() {
ALL {
override fun execQuery(invertedSearch: InvertedSearchData, words: List<String>): Set<Int> {
val results = words.mapNotNull { invertedSearch[it] }
return if (results.isEmpty()) setOf() else results.reduce {acc, set -> acc.intersect(set) }
}
}, NONE {
override fun execQuery(invertedSearch: InvertedSearchData, words: List<String>): Set<Int> {
val allIndices = invertedSearch.values.flatten().toSet()
return allIndices.subtract(ANY.execQuery(invertedSearch, words))
}
}, ANY {
override fun execQuery(invertedSearch: InvertedSearchData, words: List<String>): Set<Int> {
val results = words.mapNotNull { invertedSearch[it] }
return if (results.isEmpty()) setOf() else results.reduce {acc, set -> acc + set }
}
};
abstract fun execQuery(invertedSearch: InvertedSearchData, words: List<String>) : Set<Int>
fun execQuery(invertedSearch: InvertedSearchData, query: String) : Set<Int> {
return execQuery(invertedSearch, query.split(" ").map { it.toLowerCase() }).toSet()
}
}
class SearchProgram(private val scanner: Scanner, private val peoples: List<String>) {
private val invertedSearch: InvertedSearchData
init {
invertedSearch = buildInvertedSearch()
}
private fun buildInvertedSearch(): InvertedSearchData {
return peoples.foldRight(mutableMapOf()) { input, m ->
val words = input.split(" ").map { it.toLowerCase() }
addElement(words, m)
}
}
private fun addElement(words: List<String>, m: InvertedSearchData) =
words.foldRight(m) { word, acc ->
val indices = peoples.withIndex().filter {
it.value.toLowerCase().contains(word)
}.map { it.index }
val v = acc.getOrDefault(word, setOf()) + indices
acc[word] = v
acc
}
fun run() {
var choice = menu()
while (choice != 0) {
when (choice) {
1 -> findPerson()
2 -> printAllPeople()
else -> println("Incorrect option! Try again.")
}
choice = menu()
}
}
private fun printAllPeople() {
println("=== List of people ===")
peoples.forEach {
println(it)
}
}
private fun findPerson() {
println("Select a matching strategy: ALL, ANY, NONE")
val matchingStrategy = MatchingStrategy.valueOf(scanner.nextLine())
println("Enter a name or email to search all suitable people.")
val query = scanner.nextLine()
val found = matchingStrategy.execQuery(invertedSearch, query)
if (found.isEmpty()) {
println("No matching people found.")
} else {
println("${found.size} persons found:")
found.forEach { println(peoples[it]) }
}
}
private fun menu(): Int {
println("""
=== Menu ===
1. Find a person
2. Print all people
0. Exit
""".trimIndent())
return scanner.nextLine().toInt()
}
companion object {
fun input(scanner: Scanner): SearchProgram {
println("Enter the number of people:")
val n = scanner.nextLine().toInt()
println("Enter all people:")
val peoples = (1..n).map { scanner.nextLine() }
return SearchProgram(scanner, peoples)
}
fun input(scanner: Scanner, file:File): SearchProgram {
val peoples = file.readLines()
return SearchProgram(scanner, peoples)
}
}
}
fun main(args: Array<String>) {
if(args.isEmpty()){
print("Please add some command line arguments")
return
}
if (args[0] != "--data" || args.size < 2) {
print("Wrong command line arguments")
return
}
val scanner = Scanner(System.`in`)
val program = SearchProgram.input(scanner, File(args[1]))
program.run()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment