简体   繁体   中英

Scala extract neighbours in a List who differ by 1 (Ints)

I'm currently trying to extract neighbours in a List who differ by 1. For example if I had my List like this:

List(1,2,3,7,8,10,13,14)
//By extracting I want to get:
List(
    List(1,2,3),
    List(7,8),
    List(10),
    List(13,14)
    )

I've tried it myself by doing foldLeft, I felt like I was close but yet so far. Can anyone help me? Any suggestions? ^^ Thank you so much! :)

Here is a solution using foldRight :

val oldList = List(1, 2, 3, 7, 8, 10, 13, 14)

val newList = oldList.foldRight[List[List[Int]]](Nil)((a, b) => b match {
  case (bh @ bhh :: _) :: bt if (bhh - a == 1) => (a :: bh) :: bt
  case _ => (a :: Nil) :: b
})

So we iterate the entries backwards and either prepend to the existing head list or add a new head list depending on whether the difference is one:

Nil
(14, ...) => (14 :: Nil) :: Nil
(13, ...) => (13 :: 14 :: Nil) :: Nil
(10, ...) => (10 :: Nil) :: (13 :: 14 :: Nil) :: Nil
...

I haven't used Scala for a while so this might not be the best solution, but I hope you get the idea.

Consecutive integers will increment in line with the list index, thus we can subtract the index and they'll form groups of the same number

val li = List(1, 2, 3, 7, 8, 10, 13, 14)
val groups = li.zipWithIndex.groupBy({case (e, i) => e - i})  // group numbers
groups.values.toList.map(_.map(_._1))  // drop indices and grouping keys

Note: these will lose the ordering of unordered initial list. For your case, you can reorder with .sortBy(_.head)

  //First Part: Separates the list into ordered pairs with tail - head == 1
  val ls = List(1,2,3,7,8,10,13,14)

  val lb: ListBuffer[List[Int]] = new ListBuffer[List[Int]]()

  for (List(left,right) <- ls.sorted.sliding(2)) {
    if (right - left == 1) {
      lb += List(left, right)
    }else {
      if(!lb.flatten.toList.contains(left)) lb += List(left)
    }
  }

  println(lb.toList)

  //Second Part: Merges ordered pairs (x1, y1) and (x2, y2) when y1 == y2
  val finalLb: ListBuffer[List[Int]] = new ListBuffer[List[Int]]()

  for (List(left,right) <- lb.toList.sliding(2)) {
    if(left.tail.contains(right.head)) {
      finalLb += (left ++ right).distinct
    }else{
      finalLb += right
    }
  }

  println(finalLb.toList)

Outputs

First Part: List(List(1, 2), List(2, 3), List(7, 8), List(10), List(13, 14))
Second Part: List(List(1, 2, 3), List(7, 8), List(10), List(13, 14))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM