Как сравнить строку с другой, где между пробелами - PullRequest
0 голосов
/ 08 января 2019

Как мне сравнить эти две строки:

val a = "fit bit versa"
val b = "fitbit"

другой пример

val a = "go pro hero 6"
val b = "gopro"

другой пример

val a = "hero go pro  6"
val b = "gopro"

другой пример

val a = "hero 6 go pro"
val b = "gopro"

Я хочу получить "true" для приведенных выше сравнений, но не здесь:

val a = "vegan protein powder"
val b = "vega"

Это должно быть ложно.

В настоящее время я делаю:

def matchPattern(a:String, b: String):String=
{
      val dd = a.split(" ")
      val result = dd.map(_.toLowerCase())
      if(result contains b.toLowerCase) true 
      else false
}

Это работает для последнего случая, но не для остальных.

Есть предложения?

Ответы [ 4 ]

0 голосов
/ 08 января 2019

Вот подход с использованием for/yield, который оказался похож на подход @ leo-c. for используется для генерации скользящего окна длиной i из words для возврата оригинальных слов и комбинаций.

def matchPattern(a:String, b: String): Boolean =  {
  val words = a.split(" ")

  val combinations = words ++ (for(
    i <- (2 to words.size);
    acc <- words.sliding(i)
  ) yield acc).map(_.mkString)

  combinations.contains(b)
} 

Контрольные примеры:

val a = "fit bit versa"
val b = "fitbit"

val c = "go pro hero 6"
val d = "gopro"

val e = "hero go pro  6"  
val f = "gopro"

//false
val g = "vegan protein powder"
val h = "vega"

val i = "foo gopro bar"
val j = "gopro"

val k = "foo go pro hero bar"
val l = "goprohero"

scala> matchPattern(a,b) && matchPattern(c,d) && matchPattern(e,f) &&  !matchPattern(g,h) && matchPattern(i,j) && matchPattern(k,l) 

res175: Boolean = true
0 голосов
/ 08 января 2019

Вот один подход, использующий sliding(i), где i варьируется от 2 до количества слов в a, чтобы собрать список всех возможных объединенных смежных слов. Затем проверяется, точно ли соответствует b какой-либо из элементов в списке, как показано ниже:

def matchPattern(a: String, b: String): Boolean = {
  val words = a.toLowerCase.split("\\s+")

  val concats = (2 to words.size).foldLeft(words)(
    (acc, i) => acc ++ words.sliding(i).map(_.mkString)
  )

  concats contains b.toLowerCase
}

matchPattern("Hero go Pro 6", "gopro")
// res1: Boolean = true

matchPattern("Hero go Pro 6", "gopro6")
// res2: Boolean = true

matchPattern("Vegan protein powder", "vega")
// res3: Boolean = false
0 голосов
/ 08 января 2019

Я думаю, что это решение вашей проблемы.

def matchPattern(a: String, b: String): Boolean =
  a
    .split("\\s+")
    .tails
    .flatMap(_.inits)
    .exists(_.mkString("") == b)

Это проверит любое слово или последовательность слов в a, которое точно соответствует слову в b. Он отклонит случаи, когда b встроено в более длинное слово или последовательность слов.

Вызов split превращает строку в список слов.

Вызов tails возвращает все возможные конечные подпоследовательности списка, а inits возвращает все ведущие подпоследовательности. Комбинация двух генерирует все возможные подпоследовательности исходного списка.

Вызов exist объединяет слова и сравнивает их с тестовым словом.


Обратите внимание, что tails и inits являются ленивыми, поэтому они будут генерировать каждое решение для тестирования по очереди и останавливаются, как только решение будет найдено. Это отличается от решений, использующих sliding, которые создают каждую возможную комбинацию перед проверкой любого из них.

0 голосов
/ 08 января 2019

Полагаю, что-то вроде этого (ваши требования неполные, поэтому я интерпретировал их как "точно совпадающие с начальной частью данной строки, заканчивающейся пробелом или концом строки, за исключением, возможно, пробелов).

  @tailrec
  def matchWords(input: Seq[Char], words: Seq[Char]): Boolean = (input, words) match {
     case (Seq(), Seq() | Seq(' ', _*)) => true
     case (Seq(), _) => false
     case (Seq(a, tail@_*), Seq(b, rest@_*)) if a == b => matchWords(tail, rest)
     case (_, Seq(' ', rest@_*)) => matchWords(input, rest)
     case _ => false
   }
...