Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.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
Java 什么';s Scala';用分隔符拆分列表的惯用方法是什么?_Java_List_Scala - Fatal编程技术网

Java 什么';s Scala';用分隔符拆分列表的惯用方法是什么?

Java 什么';s Scala';用分隔符拆分列表的惯用方法是什么?,java,list,scala,Java,List,Scala,如果我有一个字符串类型的列表 scala> val items = List("Apple","Banana","Orange","Tomato","Grapes","BREAK","Salt","Pepper","BREAK","Fish","Chicken","Beef") items: List[java.lang.String] = List(Apple, Banana, Orange, Tomato, Grapes, BREAK, Salt, Pepper, BREAK, Fis

如果我有一个字符串类型的列表

scala> val items = List("Apple","Banana","Orange","Tomato","Grapes","BREAK","Salt","Pepper","BREAK","Fish","Chicken","Beef")
items: List[java.lang.String] = List(Apple, Banana, Orange, Tomato, Grapes, BREAK, Salt, Pepper, BREAK, Fish, Chicken, Beef)
如何根据特定的字符串/模式将其拆分为
n
单独的列表(
“BREAK”
,在本例中)

我曾经考虑过用
indexOf
找到
“BREAK”
的位置,然后用这种方法拆分列表,或者用类似的方法使用
takeWhile(I=>I!=“BREAK”)
,但我想知道是否有更好的方法


如果有帮助的话,我知道在
项目
列表中只有3组项目(因此有2个
“BREAK”
标记)。

这样如何:使用
扫描
来确定列表中的每个元素属于哪个部分

val l = List("Apple","Banana","Orange","Tomato","Grapes","BREAK","Salt","Pepper","BREAK","Fish","Chicken","Beef")
val count = l.scanLeft(0) { (n, s) => if (s=="BREAK") n+1 else n } drop(1)
val paired = l zip count
(0 to count.last) map { sec => 
  paired flatMap { case (x, c) => if (c==sec && x!="BREAK") Some(x) else None }  
}
// Vector(List(Apple, Banana, Orange, Tomato, Grapes), List(Salt, Pepper), List(Fish, Chicken, Beef))
def splitBySeparator[T](l:List[T],sep:T):List[List[T]={
l、 span(!=sep)匹配{
案例(hd,::tl)=>hd::拆分器(tl,sep)
案例(hd,)=>列表(hd)
}
}
结果:

res1: List[List[String]] = List(List(Apple, Banana, Orange, Tomato, Grapes), List(Salt, Pepper), List(Fish, Chicken, Beef))
更新:上述版本虽然简洁有效,但存在两个问题:它不能很好地处理边缘情况(如
List(“BREAK”)
List(“BREAK”、“Apple”、“BREAK”)
),并且不是尾部递归的。因此,下面是另一个(强制)版本来解决这个问题:

import collection.mutable.ListBuffer
def splitBySeparator[T](l:Seq[T],sep:T):Seq[Seq[T]={
val b=ListBuffer(ListBuffer[T]())
l foreach{e=>
如果(e==sep){
如果(!b.last.isEmpty)b+=ListBuffer[T]()
}
否则b.last+=e
}
b、 映射(toSeq)
}
它在内部使用了一个
ListBuffer
,这与我在第一个版本的
splitBySeparator
中使用的
List.span
的实现非常相似。另一个选项是:

val l=Seq(1,2,3,4,5,9,1,2,3,4,5,9,1,2,3,4,5,9,1,2,2,3,4,5,9,1,2,3,4,5)
l、 foldLeft(Seq(Seq.empty[Int])){
(acc,i)=>
如果(i==9)acc:+Seq.empty
else acc.init:+(acc.last:+i)
}
//产生:
列表(列表(1,2,3,4,5)、列表(1,2,3,4,5)、列表(1,2,3,4,5)、列表(1,2,3,4,5))

这也不是尾部递归,但在边缘情况下也可以:

def splitsies[T](l:List[T], sep:T) : List[List[T]] = l match {
  case head :: tail =>
    if (head != sep)
      splitsies(tail,sep) match {
        case h :: t => (head :: h) :: t
        case Nil => List(List(head))
      }
    else
      List() :: splitsies(tail, sep)
  case Nil => List()
}
唯一令人讨厌的是:

scala> splitsies(List("BREAK","Tiger"),"BREAK")
res6: List[List[String]] = List(List(), List(Tiger))
如果您想更好地处理分隔符启动的情况,请查看与Martin中使用span类似的内容(针对一个稍微不同的问题)

此处“,”是唯一的分隔符,不会出现在项目列表中的任何字符串中。如果需要,我们可以选择其他分隔符

items.mkString(“,”)
将所有内容组合成一个字符串

.split("BREAK") // which we then split using "BREAK" as delimiter to get a list

.map("(^,|,$)".r.replaceAllIn(_, "")) // removes the leading/trailing commas of each element of the list in previous step

.map(_.split(",")) // splits each element using comma as seperator to give a list of lists


scala> val q = items.mkString(",").split("BREAK").map("(^,|,$)".r.replaceAllIn(_, "")).map(_.split(","))
q: Array[Array[String]] = Array(Array(Apple, Banana, Orange, Tomato, Grapes), Array(Salt, Pepper), Array(Fish, Chicken, Beef))

scala> q(0)
res21: Array[String] = Array(Apple, Banana, Orange, Tomato, Grapes)

scala> q(1)
res22: Array[String] = Array(Salt, Pepper)

scala> q(2)
res23: Array[String] = Array(Fish, Chicken, Beef)
使用List.unfold(Scala 2.13及更高版本): 代码在上运行

使用
reverse
+
foldLeft
def splitatement[T](列表:列表[T],元素:T):列表[list[T]={
list.reverse.foldLeft(list(list[T]())((l,currentElement)=>{
if(currentElement==元素){
List()::l
}否则{
(currentElement::l.head)::l.tail
}
})
}
代码在上运行

使用
foldRight
def splitBySeparator[T](列表:列表[T],九月:T):列表[list[T]={
foldRight(list(list[T]())((s,l)=>{
如果(sep==s){
List()::l
}否则{
(s::l.头)::l.尾
}
}).filter(u.nonEmpty)
}

代码运行于。

splitAt可能更合适,但恼人的是,BREAK仍然存在,您需要手动删除它。这个问题类似,但不完全相同:+1对Luigi来说,这是Martin Odersky自己的答案:)这不是尾部递归,所以在长列表中要小心使用,很好的一点——我的名单会比较短,所以我不必担心。@stew:的确如此。我用一个尾部递归的版本更新了答案(同时有大量的边缘案例)。我确实遇到了
列表(“BREAK”)
边缘案例,因此感谢您的修订,在
列表的末尾添加元素是不有效的
val q = items.mkString(",").split("BREAK").map("(^,|,$)".r.replaceAllIn(_, "")).map(_.split(","))
.split("BREAK") // which we then split using "BREAK" as delimiter to get a list

.map("(^,|,$)".r.replaceAllIn(_, "")) // removes the leading/trailing commas of each element of the list in previous step

.map(_.split(",")) // splits each element using comma as seperator to give a list of lists


scala> val q = items.mkString(",").split("BREAK").map("(^,|,$)".r.replaceAllIn(_, "")).map(_.split(","))
q: Array[Array[String]] = Array(Array(Apple, Banana, Orange, Tomato, Grapes), Array(Salt, Pepper), Array(Fish, Chicken, Beef))

scala> q(0)
res21: Array[String] = Array(Apple, Banana, Orange, Tomato, Grapes)

scala> q(1)
res22: Array[String] = Array(Salt, Pepper)

scala> q(2)
res23: Array[String] = Array(Fish, Chicken, Beef)
val p: String => Boolean = _ != "BREAK"

val result: List[List[String]] = List.unfold(items) {
  case Nil =>
    None
  case l if p(l.head) =>
    Some(l.span(p))
  case _ :: tail =>
    Some(tail.span(p))
}