3

I know lists are immutable but I'm still confused on how I would go about this. I have two lists of strings - For example:

var list1: List[String] = List("M", "XW1", "HJ", "K")
var list2: List[String] = List("M", "XW4", "K", "YN")

I want to loop through these lists and see if the elements match. If it doesn't, the program would immediately return false. If it is a match, it will continue to iterate until it finds an element that begins with X. If it is indeed an X, I want to return true regardless of whether the number is the same or not.

Problem I'm having is that currently I have a conditional stating that if the two elements do not match, return false immediately. This is a problem because obviously XW1 and XW4 are not the same and it will return false. How can I bypass this and determine that it is a match to my eyes regardless of the number?

I also have a counter a two length variables to account for the fact the lists may be of differing length. My counter goes up to the shortest list: for (x <- 0 to (c-1)) (c being the counter).

2
  • What do you expect the result of provided sample list1 and list2? Commented Sep 22, 2020 at 19:23
  • This example should return true. Commented Sep 22, 2020 at 19:31

4 Answers 4

4

You want to use zipAll & forall.

def compareLists(l1: List[String], l2: List[String]): Boolean =
  l1.zipAll(l2, "", "").forall {
    case (x, y) =>
      (x == y) || (x.startsWith("X") && y.startsWith("X"))
  }

Note that I am assuming an empty string will always be different than any other element.

Sign up to request clarification or add additional context in comments.

2 Comments

this is not what he expect I guess! This solution returns false for given inputs but expected is true
@PritamKadam so, let me see if I understood correctly. You start checking that each pair of elements are the same, if they are not the same and they both do not start with an X then return false, if they both start with an X return true. If one list is smaller than the other return false. If all pairs were equal and we never found a pair whose elements started with X we also return true. If two elements are the same but they both start with X return true.
2

If I understand your requirement correctly, to be considered a match, 1) each element in the same position of the two lists being simultaneously iterated must be the same except when both start with X (in which case it should return true without comparing any further), and 2) both lists must be of the same size.

If that's correct, I would recommend using a simple recursive function like below:

def compareLists(ls1: List[String], ls2: List[String]): Boolean = (ls1, ls2) match {
  case (Nil, Nil) =>
    true
  case (h1 :: t1, h2 :: t2) =>
    if (h1.startsWith("X") && h2.startsWith("X"))
      true  // short-circuiting
    else
      if (h1 != h2)
        false
      else
        compareLists(t1, t2)
  case _ =>
    false
}

Comments

0

Based on your comment that, result should be true for lists given in question, you could do something like this:

val list1: List[String] = List("M", "XW1", "HJ", "K")
val list2: List[String] = List("M", "XW4", "K", "YN")


val (matched, unmatched) = list1.zipAll(list2, "", "").partition { case (x, y) => x == y }

val result = unmatched match {
  case Nil         => true
  case (x, y) :: _ => (x.startsWith("X") && y.startsWith("X"))
}

Comments

0

You could also use cats foldM to iterate through the lists and terminate early if there is either (a) a mismatch, or (b) two elements that begin with 'X':

import cats.implicits._

val list1: List[String] = List("M", "XW1", "HJ", "K")
val list2: List[String] = List("M", "XW4", "K", "YN")

list1.zip(list2).foldM(()){
  case (_, (s1, s2)) if s1 == s2 => ().asRight
  case (_, (s1, s2)) if s1.startsWith("X") && s2.startsWith("X") => true.asLeft
  case _ => false.asLeft
}.left.getOrElse(false)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.