代码之家  ›  专栏  ›  技术社区  ›  Ankit

Scala—如何以函数方式循环列表

  •  0
  • Ankit  · 技术社区  · 6 年前

    for (item <- dataList)
    {
       // Code to compare previous list element
       prevElement = item
    }
    

    上面的代码可以正常工作并给出正确的结果,但我想探索编写相同代码的功能性方法。

    3 回复  |  直到 6 年前
        1
  •  5
  •   scalabling    6 年前

    有许多不同的解决方案。也许最通用的方法是使用helper函数:

    // This example finds the minimum value (the hard way) in a list of integers. It's
    // not looking at the previous element, as such, but you can use the same approach.
    // I wanted to make the example something meaningful.
    def findLowest(xs: List[Int]): Option[Int] = {
    
      @tailrec // Guarantee tail-recursive implementation for safety & performance.
      def helper(lowest: Int, rem: List[Int]): Int = {
    
        // If there are no elements left, return lowest found.
        if(rem.isEmpty) lowest
    
        // Otherwise, determine new lowest value for next iteration. (If you need the
        // previous value, you could put that here.)
        else {
          val newLow = Math.min(lowest, rem.head)
          helper(newLow, rem.tail)
        }
      }
    
      // Start off looking at the first member, guarding against an empty list.
      xs match {
        case x :: rem => Some(helper(x, rem))
        case _ => None
      }
    }
    

    在这种特殊情况下,可以用 fold .

    def findLowest(xs: List[Int]): Option[Int] = xs match {
      case h :: _ => Some(xs.fold(h)((b, m) => Math.min(b, m)))
      case _ => None
    }
    

    def findLowest(xs: List[Int]): Option[Int] = xs match {
      case h :: _ => Some(xs.foldLeft(h)(Math.min))
      case _ => None
    }
    

    在这种情况下,我们使用 zero 论据 折叠

    如果这看起来太抽象了,你能发布更多关于你想在你的循环中做什么的细节吗,我可以在我的回答中解决这个问题吗?

    更新 DateRange (需要用实际类型替换)。你还必须确定 overlap merge

    // Determine whether two date ranges overlap. Return true if so; false otherwise.
    def overlap(a: DateRange, b: DateRange): Boolean = { ... }
    
    // Merge overlapping a & b date ranges, return new range.
    def merge(a: DateRange, b: DateRange): DateRange = { ... }
    
    // Convert list of date ranges into another list, in which all consecutive,
    // overlapping ranges are merged into a single range.
    def mergeDateRanges(dr: List[DateRange]): List[DateRange] = {
    
      // Helper function. Builds a list of merged date ranges.
      def helper(prev: DateRange, ret: List[DateRange], rem: List[DateRange]):
      List[DateRange] = {
    
        // If there are no more date ranges to process, prepend the previous value
        // to the list that we'll return.
        if(rem.isEmpty) prev :: ret
    
        // Otherwise, determine if the previous value overlaps with the current
        // head value. If it does, create a new previous value that is the merger
        // of the two and leave the returned list alone; if not, prepend the
        // previous value to the returned list and make the previous value the
        // head value.
        else {
          val (newPrev, newRet) = if(overlap(prev, rem.head)) {
            (merge(prev, rem.head), ret)
          }
          else (rem.head, prev :: ret)
    
          // Next iteration of the helper (I missed this off, originally, sorry!)
          helper(newPrev, newRet, rem.tail)
        }
      }
    
      // Start things off, trapping empty list case. Because the list is generated by pre-pending elements, we have to reverse it to preserve the order.
      dr match {
        case h :: rem => helper(h, Nil, rem).reverse // <- Fixed bug here too...
        case _ => Nil
      }
    }
    
        2
  •  0
  •   Tanel    6 年前

    val list = Seq("one", "two", "three", "one", "one")
    val result = list.sliding(2).collect { case Seq(a,b) => a.equals(b)}.toList
    

    列表(假,假,假,真)

    上一种方法的另一种方法是,您可能希望获得以下值:

    val result = list.sliding(2).collect { 
      case Seq(a,b) => if (a.equals(b)) Some(a) else None
      case _ => None
    }.toList.filter(_.isDefined).map(_.get)
    

    这将提供以下信息:

    列表(一)

    val list = Seq("one", "two", "three", "one")
    
    for {
      item1 <- list
      item2 <- list
      _ <- Option(println(item1 + ","+ item2))
    } yield ()
    

    这将导致:

    one,one
    one,two
    one,three
    one,one
    two,one
    two,two
    two,three
    two,one
    three,one
    three,two
    three,three
    three,one
    one,one
    one,two
    one,three
    one,one
    
        3
  •  0
  •   Shankar Shastri    6 年前

    如果您没有改变列表,并且只尝试并排比较两个元素。

    def cmpPrevElement[T](l: List[T]): List[(T,T)] = {
      (l.indices).sliding(2).toList.map(e => (l(e.head), l(e.tail.head)))
    }