通过将列表项与其邻居进行比较来对列表项进行分组 [英] Grouping list items by comparing them with their neighbors
问题描述
根据相邻值将值列表分组的最优雅方式是什么?
What is the most elegant way of grouping a list of values into groups based on their neighbor values?
我拥有的更广泛的上下文是有一个行列表,需要将其分组为段落.我想说的是,如果两行之间的垂直差异低于阈值,则它们在同一段落中.
The wider context I have is having a list of lines, that need to be grouped into paragraphs. I want to be able to say that if the vertical difference between two lines is lower than threshold, they are in the same paragraph.
我最终以不同的方式解决了这个问题,但我想知道这里的正确解决方案.
I ended up solving this problem differently, but I'm wondering about the correct solution here.
case class Box(y: Int)
val list = List(Box(y=1), Box(y=2), Box(y=5))
def group(list: List[Box], threshold: Int): List[List[Box]] = ???
val grouped = group(list, 2)
> List(List(Box(y=1), Box(y=2)), List(Box(y=5)))
我看过groupBy()
,但这一次只能处理一个元素.我还尝试了一种使用 sliding()
,但是从原始集合中检索元素变得很尴尬.
I have looked at groupBy()
, but that can only work with one element at a time. I have also tried an approach that involved pre-computing differences using sliding()
, but then it becomes awkward to retrieve the elements from the original collection.
推荐答案
这是一个单线.概括类型留给读者作为练习.
It's a one liner. Generalising types left as an exercise for the reader.
使用整数和绝对差异而不是行和间距来避免混乱.
Using ints and absolute difference rather than lines and spacing to avoid clutter.
val zs = List(1,2,4,8,9,10,15,16)
def closeEnough(a:Int, b:Int) = (Math.abs(b -a) <= 2)
zs.drop(1).foldLeft(List(List(zs.head)))
((acc, e)=> if (closeEnough(e, acc.head.head))
(e::acc.head)::acc.tail
else
List(e)::acc)
.map(_.reverse)
.reverse
// List(List(1, 2, 4), List(8, 9, 10), List(15, 16))
或者两个衬里以获得轻微的效率提升
Or a two liner for a slight efficiency gain
val ys = zs.reverse
ys.drop(1).foldLeft(List(List(ys.head)))
((acc, e)=> if (closeEnough(e, acc.head.head))
(e::acc.head)::acc.tail
else
List(e)::acc)
// List(List(1, 2, 4), List(8, 9, 10), List(15, 16))
这篇关于通过将列表项与其邻居进行比较来对列表项进行分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!