Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 如何基于prev和curr元素上的条件拆分迭代器?_Scala - Fatal编程技术网

Scala 如何基于prev和curr元素上的条件拆分迭代器?

Scala 如何基于prev和curr元素上的条件拆分迭代器?,scala,Scala,我想将一个元素列表拆分为一个列表列表,以便内部列表中的相邻元素满足给定条件 一个简单的条件是相邻元素相等。如果输入是List(1,1,1,2,2,3,3,3,3)输出是List(List(1,1,1)、List(2,2)、List(3,3)) 另一个条件可能是当前元素应大于上一个元素。然后,如果输入是List(1,2,3,1,4,6,5,7,8),则输出是List(List(1,2,3)、List(1,4,6)、List(5,7,8))。如果该方法能够作用于迭代器,那将是一件非常美妙的事情。方法

我想将一个元素列表拆分为一个列表列表,以便内部列表中的相邻元素满足给定条件

一个简单的条件是相邻元素相等。如果输入是
List(1,1,1,2,2,3,3,3,3)
输出是
List(List(1,1,1)、List(2,2)、List(3,3))

另一个条件可能是当前元素应大于上一个元素。然后,如果输入是
List(1,2,3,1,4,6,5,7,8)
,则输出是
List(List(1,2,3)、List(1,4,6)、List(5,7,8))
。如果该方法能够作用于
迭代器
,那将是一件非常美妙的事情。方法的typedef是

def method[A](lst:List[A], cond:(A,A)=>Boolean):List[List[A]]
def method[A](lst:Iterator[A], cond:(A,A)=>Boolean):Iterator[Iterator[A]]
这里有一些接近(我相信)你要求的东西。唯一的问题是,它总是为结果生成列表列表,而不是基于输入类型:

  val iter = Iterator(1,1,2,2,2,3,3,3)
  val list = List(4,5,5,5,5,6,6)

  def same(a:Int,b:Int) = a == b
  def gt(a:Int, b:Int) = b > a

  println(groupByPred(iter, same))
  println(groupByPred(list, gt))

  def groupByPred[L <: TraversableOnce[T], T](trav:L, cond:(T,T) => Boolean):List[List[T]] = {
    val (ret, inner) = 
      trav.foldLeft((List.empty[List[T]], List.empty[T])){
        case ((acc, list), el) if list.isEmpty || cond(list.head, el) => (acc,el :: list)
        case ((acc, list), el)  => (list.reverse :: acc,el :: List.empty)
      }
    (inner.reverse :: ret).reverse
  }
试试这个

将列表的头作为列表的第一个元素的第一个元素。然后,如果条件成立,则将内容添加到第一个列表中。如果没有,则以当前条目作为第一个元素启动一个新列表

内部列表和外部列表都以错误的顺序构造。因此,反转外部列表的每个元素(使用map),然后反转外部列表

  val xs = List(1, 1, 1, 2, 2, 3, 3, 3, 3)
  val ys = List(1, 2, 3, 1, 4, 6, 5, 7, 8)

  def method[A](lst: List[A], cond: (A, A) => Boolean): List[List[A]] = {
    lst.tail.foldLeft(List(List(lst.head))) { (acc, e) =>
      if (cond(acc.head.head, e))
        (e :: acc.head) :: acc.tail
      else List(e) :: acc
    }.map(_.reverse).reverse
  }

method(xs, { (a: Int, b: Int) => a == b })
//> res0: List[List[Int]] = List(List(1, 1, 1), List(2, 2), List(3, 3, 3, 3))
method(ys, { (a: Int, b: Int) => a < b })
//> res1: List[List[Int]] = List(List(1, 2, 3), List(1, 4, 6), List(5, 7, 8))
val xs=List(1,1,1,2,2,3,3,3,3)
val ys=列表(1,2,3,1,4,6,5,7,8)
定义方法[A](lst:List[A],条件:(A,A)=>布尔值):List[List[A]={
lst.tail.foldLeft(List(List(lst.head)){(acc,e)=>
如果(条件(根据头部,e))
(e::acc.head)::acc.tail
其他清单(e)::acc
}.map(u.reverse).reverse
}
方法(xs,{(a:Int,b:Int)=>a==b})
//>res0:List[List[Int]=List(List(1,1,1),List(2,2),List(3,3,3))
方法(ys,{(a:Int,b:Int)=>ares1:List[List[Int]=List(List(1,2,3),List(1,4,6),List(5,7,8))
迭代器重载

def method[A](iter:Iterator[A], cond: (A, A) => Boolean): List[List[A]] = {
 val h = iter.next
   iter.foldLeft(List(List(h))) { (acc, e) =>
     if (cond(acc.head.head, e))
       (e :: acc.head) :: acc.tail
     else List(e) :: acc
   }.map(_.reverse).reverse
 }

method(xs.toIterator, { (a: Int, b: Int) => a == b })
//> res0: List[List[Int]] = List(List(1, 1, 1), List(2, 2), List(3, 3, 3, 3))
method(ys.toIterator, { (a: Int, b: Int) => a < b })
//> res1: List[List[Int]] = List(List(1, 2, 3), List(1, 4, 6), List(5, 7, 8))
def方法[A](iter:Iterator[A],cond:(A,A)=>Boolean):List[List[A]={
val h=iter.next
iter.foldLeft(List(List(h)){(acc,e)=>
如果(条件(根据头部,e))
(e::acc.head)::acc.tail
其他清单(e)::acc
}.map(u.reverse).reverse
}
方法(xs.toIterator,{(a:Int,b:Int)=>a==b})
//>res0:List[List[Int]=List(List(1,1,1),List(2,2),List(3,3,3))
方法(ys.toIterator,{(a:Int,b:Int)=>ares1:List[List[Int]=List(List(1,2,3),List(1,4,6),List(5,7,8))
更通用的版本(这里有@cmbaxter的一些想法),可用于列表、迭代器和任何可以遍历一次的对象:

def method[A, T <: TraversableOnce[A]](trav: T, cond: (A, A) => Boolean)
: List[List[A]] = {
    trav.foldLeft(List(List.empty[A])) { (acc, e) =>
      if (acc.head.isEmpty || !cond(acc.head.head, e)) List(e) :: acc
      else (e :: acc.head) :: acc.tail
    }.map(_.reverse).reverse
  }
def方法[A,T布尔值)
:List[列表[A]={
trav.foldLeft(List(List.empty[A]){(acc,e)=>
如果(acc.head.isEmpty | | |!cond(acc.head.head,e))列表(e)::acc
其他(e::acc.head)::acc.tail
}.map(u.reverse).reverse
}

您可以在递归函数中使用
滑动
span
以获得所需的效果。此快速且肮脏的版本效率较低,但比某些替代版本更简洁:

def method[A](lst: TraversableOnce[A], cond: (A, A) => Boolean): List[List[A]] = {
    val iterable = lst.toIterable
    iterable.headOption.toList.flatMap { head => 
        val (next, rest) = iterable.sliding(2).filter(_.size == 2).span(x => cond(x.head, x.last))
        (head :: next.toList.map(_.last)) :: method(rest.map(_.last), cond)
    }
}
如果要延迟执行代码,可以返回一个
迭代器[List[A]
,而不是
List[List[A]]

def method[A](lst: TraversableOnce[A], cond: (A, A) => Boolean): Iterator[List[A]] = {
    val iterable = lst.toIterable
    iterable.headOption.toIterator.flatMap { head => 
        val (next, rest) = iterable.sliding(2).filter(_.size == 2).span(x => cond(x.head, x.last))
        Iterator(head :: next.toList.map(_.last)) ++ method(rest.map(_.last), cond)
    }
}  
def method[A](lst: TraversableOnce[A], cond: (A, A) => Boolean): Iterator[Iterator[A]] = {
    val iterable = lst.toIterable
    iterable.headOption.toIterator.flatMap { head => 
        val (next, rest) = iterable.sliding(2).filter(_.size == 2).span(x => cond(x.head, x.last))
        Iterator(Iterator(head) ++ next.toIterator.map(_.last)) ++ method(rest.map(_.last), cond)
    }
} 
您可以验证这是惰性的:

val x = (Iterator.range(0, 10) ++ Iterator.range(3, 5) ++ Iterator.range(1, 3)).map(x => { println(x); x })
val iter = method(x, (x: Int, y: Int) => x < y) //Only prints 0-9, and then 3!
iter.take(2).toList //Prints more
iter.toList //Prints the rest
作为一个相对不相关的补充说明,当您拥有此表单的通用参数时,最好使用两个参数列表:

def method[A](lst: TraversableOnce[A])(cond: (A, A) => Boolean)
当您有两个这样的参数列表时,类型推断可能会更智能一些:

//No need to specify parameter types on the anonymous function now!
method(List(1, 3, 2, 3, 4, 1, 8, 1))((x, y) => x < y).toList
//You can now even use underscore anonymous function notation!
method(List(1, 4, 2, 3, 4, 1, 8))(_ < _)
//现在无需在匿名函数上指定参数类型!
方法(列表(1,3,2,3,4,1,8,1))((x,y)=>x
我认为您的第一个示例没有多大意义。您所说的“相邻元素相等”是什么意思?
2
的相邻元素在列表中的任何位置都不相等。对于
列表(…,prev,curr,next)例如,
,应该
prev==next
或者应该
prev==curr
或者
curr==next
,但是它不起作用。
方法(List(1,2,3,1,4,6,5,7,8),{(a:Int,b:Int)=>a
给出
列表(List(1,2,3),List(),List(1,4,6),List(5,7,8))
(注意不需要的空列表-也有一个用于==的情况)。它在迭代器上不起作用。运行您为我编写的代码返回
list(list(1,2,3),list(1,4,6),list(5,7,8))
,根据需要--你确定要运行这个确切的代码吗?至于
迭代器
,这个解决方案本身依赖于
zip
,因此它不能很好地与
迭代器
一起工作。当然,如果这是一个选项,你可以调用
toList
。@Paul我已经更新了答案,因此它现在可以与
迭代器一起工作。
。Yes,我确定(我剪切并粘贴了Scala IDE 4.0工作表中的代码和结果)。您最新修改的版本有效,尽管我看到我们在方法中使用了list.last。如果我有一个大型迭代器,这不是一个问题吗。理想情况下,我会返回迭代器[iterator[a]]。但我喜欢这个解决方案。非常感谢
//No need to specify parameter types on the anonymous function now!
method(List(1, 3, 2, 3, 4, 1, 8, 1))((x, y) => x < y).toList
//You can now even use underscore anonymous function notation!
method(List(1, 4, 2, 3, 4, 1, 8))(_ < _)