Scala:将列表拆分为多个部分

时间:2016-07-14 06:26:49

标签: list scala

假设我有一个元组列表......

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <local:MyControl></local:MyControl>
</Grid>

...此列表按日期排序......

val l: List[(String, String, Date)] 

现在我想将这个排序列表拆分成多个列表。分割应该发生在日期差异大于3天的元组之间。什么是一个好的和高效的方法呢?

谢谢和问候!

修改

这是一个例子: 输入(已排序):

  

列表((&#34; a1&#34;,&#34; b1&#34;,&#34; 2016-01-30&#34;),(&#34; a2&#34;,&# 34; b2&#34;,&#34; 2016-02-01&#34;),(&#34; a3&#34;,&#34; b3&#34;,   &#34; 2016-02-20&#34;),(&#34; a4&#34;,&#34; b4&#34;,&#34; 2016-02-23&#34;),(&# 34; a5&#34;,&#34; b5&#34;,&#34; 2016-02-25&#34;))

预期产出:

  

列表(列出(&#34; a1&#34;,&#34; b1&#34;,&#34; 2016-01-30&#34;),(&#34; a2&#34;, &#34; b2&#34;,&#34; 2016-02-01&#34;)),列表((&#34; a3&#34;,&#34; b3&#34;,   &#34; 2016-02-20&#34;),(&#34; a4&#34;,&#34; b4&#34;,&#34; 2016-02-23&#34;),(&# 34; a5&#34;,&#34; b5&#34;,&#34; 2016-02-25&#34;)))

4 个答案:

答案 0 :(得分:1)

哎呀,如果这是派对,我可能会把我的2美分扔到一边。

sorted.init.foldRight(List(List(sorted.last))){ (tup,acc) => 
  if (acc.head.head._3 - tup._3 > /*test for time-gap here*/) 
    List(tup)::acc  // gap too big, start new sub-List
  else
    (tup::acc.head)::acc.tail  // prepend to current sub-List
}

答案 1 :(得分:0)

我稍微简化了类型,代码只是说明了这个概念。如果没有toList转换,效果可能会更好。

type MyTuple = (String, Int)

val sorted: List[MyTuple] = List(
    ("a", 1),
    ("a", 2),
    ("a", 3),
    ("b", 7),
    ("b", 9),
    ("c", 13),
    ("c", 15),
    ("c", 16)
)

def test(a: MyTuple, b: MyTuple): Boolean = b._2 - a._2 > 3

// We prepend the head so that the first sliding pair will have distance 0
val lists = (sorted.head :: sorted)
  .sliding(2)
  .map { case List(a, b) => (b, test(a, b)) }
  .toList

def split(list: List[(MyTuple, Boolean)]): List[List[MyTuple]] = list match {
  case Nil => Nil
  case head :: tail => {
    val (l1, l2) = tail.span(!_._2)
    (head :: l1).map(_._1) :: split(l2)
  }
}

val splitLists = split(lists).map(_.map(_._1))
println(splitLists.mkString("\n"))

输出:

List(a, a, a)
List(b, b)
List(c, c, c)

答案 2 :(得分:0)

为方便起见,我已将Ints替换为日期,但原则是相同的。

   val data = List(
      ("a","a", 10),
      ("a","b", 30),
      ("a","b", 11),
      ("a","b", 33),
      ("s","c", 37),
      ("a","c", 26),
      ("a","d", 22),
      ("m","a", 18),
      ("t","a", 15)
    )
    val sortedData = data.sortWith ((a,b)=> a._3 < b._3)
    println(s"$sortedData")
    val splitPass = sortedData.foldLeft(List[(String, String,Int)](), List[List[(String, String,Int)]](), sortedData.head._3){
      case ((cl, acc, ld),nt) =>
        if (nt._3-ld>3)
          (List(nt), cl.reverse ::acc, nt._3)
        else
          (nt:: cl, acc, nt._3)
    }
    val (fl, fa, _) = splitPass
    val res = (if (fl.isEmpty) fa else fl :: fa).reverse
    println(s"$res")

这给出了排序列表:

List((a,a,10), (a,b,11), (t,a,15), (m,a,18), (a,d,22), (a,c,26), (a,b,30), (a,b,33), (s,c,37))

和结果列表:

List(List((a,a,10), (a,b,11)), List((t,a,15), (m,a,18)), List((a,d,22)), List((a,c,26)), List((a,b,30), (a,b,33)), List((s,c,37)))

这样做是单次通过排序列表,构建一个累加器,包括(当前组中的项目列表,已完成组列表,最后添加项目的Int [Date])。这里有两个空列表和列表中第一个项目的日期。

对于源列表中的每个项目,如果它接近上一个项目,它将被添加到当前组,如果它远离前一个项目,则关闭并添加当前组到完成的gorups列表,当前项目包含新列表中的第一项,当前项目的日期成为下一次检查的参考日期。如果你想打破日期不同于当前组中最早的日期,可以很容易地将else分支更改为传递ld而不是nt._3。

最后,您需要将任何未完成的组添加到最终的组集合中。

这两个反向是必要的,因为这些列表在典型的功能风格中向后构建(因为它的价格更便宜)并在完成时反转。

答案 3 :(得分:0)

这是一种非常干净的线性时间(单程)方法:

type Date = Int  // For simplicity in the example

val sorted: List[(String,String,Date)] = List(("a1", "b1", 1),
                                              ("a1", "b1", 2),
                                              ("a1", "b1", 6),
                                              ("a1", "b1", 8),
                                              ("a1", "b1", 10),
                                              ("a1", "b1", 15),
                                              ("a1", "b1", 16))

val result = sorted.sliding(2).foldLeft(Vector(Vector(sorted.head))) { 
  case (z, List(t1, t2)) => 
    if (t2._3 - t1._3 > 3) z :+ Vector(t2)
    else                   z.init :+ (z.last :+ t2)
}

result.foreach(println)
// Vector((a1,b1,1), (a1,b1,2))
// Vector((a1,b1,6), (a1,b1,8), (a1,b1,10))
// Vector((a1,b1,15), (a1,b1,16))

您可以单独处理sorted.length() < 2的特殊情况。