Search code examples
scalafunctional-programmingcomparison-operators

Comparing lists - checking if one list is a segment of second one


Good morning everyone (or good evening :)), I have problem with checking if one list is segment of second one. All elements of first list must be the first elements of second list.

For example

L1=[1,2,3,4]
L2=[3,4,5,6]
>false

L1=[1,2,3,4]
L2=[1,2,3,4,5,6,7,8]
>true

L1=[-1,-7,3,2]
L2=[1,2,3,4,5]
>false

I know it would be easy to use loop and then comparing elements, but i want to do it in functional way. I had idea, but it was not clever, to stick both lists (with zip, for example), then unzip it, chenge to set and compare if it has the same length then second list, but that method do not look good.

I'm new in Scala, so sorry for propably stupid question. I don't please for code, but for some advices! :)

Thanks guys!


Solution

  • An idiomatic approach to this; let

    val a = (1 to 5).toList    
    val b = (2 to 4).toList
    val c = List(2,7,4)
    

    Then

    a.tails.collectFirst { case l if (l.startsWith(b)) => true }
    res: Option[Boolean] = Some(true)
    

    and

    a.tails.collectFirst { case l if (l.startsWith(c)) => true }
    res: Option[Boolean] = None
    

    Here tails will create an iterator over each sublist from an item in the list to the last item in the list; startsWith will succeed only if our string of interest is the start of any sublist; collectFirst will deliver an Option[Boolean] at the first successful response from startsWith, else it will deliver a None that indicates no match.

    In order to wrap up this idea, consider this implicit class,

    implicit class RichList[A](val seg: List[A]) extends AnyVal {
      def isSegmentOf(l: List[A]) = {
        l.tails.collectFirst { case t if (t.startsWith(seg)) => true }
      }
    }
    

    Thus

    b.isSegmentOf(a)
    res: Option[Boolean] = Some(true)
    
    c.isSegmentOf(a)
    res: Option[Boolean] = None