假设我有一个元组列表......
<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;)))
答案 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
的特殊情况。