The solution proposed by @jwvh in the comments:
companyNames.view.filter(_.startsWith(input)).take(numberOfSuggest).toSeq
is good when you have several dozen company names, but in the worst case you'll have to check every single company name. If you have thousands of company names and many requests per second, this has a chance to become a serious bottleneck.
A better approach might be to sort the company names and use binary search to find the first potential result in O(L log N), where L is the average length of a company name:
import scala.collection.imuutable.ArraySeq // in Scala 2.13 class SuggestService(companyNames: Seq[String]) { // in Scala 2.12 use companyNames.toIndexedSeq.sorted private val sortedNames = companyNames.to(ArraySeq).sorted @annotation.tailrec private def binarySearch(input: String, from: Int = 0, to: Int = sortedNames.size): Int = { if (from == to) from else { val cur = (from + to) / 2 if (sortedNames(cur) < input) binarySearch(input, cur + 1, to) else binarySearch(input, from, cur) } } def suggest(input: String, numberOfSuggest: Int): Seq[String] = { val start = binarySearch(input) sortedNames.view .slice(start, start + numberOfSuggest) .takeWhile(_.startsWith(input)) .toSeq } }
Note that the built-in binary search in scala (sortedNames.search) returns any result, not necessarily the first one. And the built-in binary search from Java works either on Arrays (Arrays.binarySearch) or on Java collections (Collections.binarySearch). So in the code above I've provided an explicit implementation of the lower bound binary search.
If you need still better performance, you can use a trie data structure. After traversing the trie and finding the node corresponding to input in O(L) (may depend on trie implementation), you can then continue down from this node to retrieve the first numberOfSuggest results. The query time doesn't depend on N at all, so you can use this method with millions company names.
resultCompanyNameslazy?companyNames.view.filter(_.startsWith(input)).take(numberOfSuggest).toSeq