【问题标题】:In Scala, what is the right way to sort a list on a composite key在Scala中,对复合键上的列表进行排序的正确方法是什么
【发布时间】:2014-04-15 13:04:03
【问题描述】:

我正在尝试从列表中获取前 N-1 个元素。我在 SO 中浏览过类似的帖子,例如 herehere。我已经了解这些帖子中提出的解决方案背后的动机。但是,我认为我的问题有点不同。

我有一些元素的排序(降序)列表。让我们假设它已经以一种有效的方式排序,因为这不是重点。

头部是我得到的最上面的。但是,列表的其余部分中有 0 个或多个重复项。每个重复项的 attr1head 的相同。我想提取这些重复项(如果有)。然后我想在第二个属性 attr2 上对这个(顶部 + 重复)列表进行排序。换句话说,我想对复合​​键进行排序:首先按 Key_1,然后 - 对于相同的 Key_1 - 按 Key_2。

假设列表中的一个元素是一对。

case class PairOfAttrs(val int attr1,val int attr2)

/* .. more code here ... */

// Now, we obtain a sorted (descending) list of PairOfAttrs below
// Ordering is based on the value of attr1 (key_1)
val sortedPairsFirstAttr = .. // Seq(Pair1,Pair2,Pair3,Pair4....Pairn)

val top = sortedPairsFirstAttr.head

显然,top 的 attr1 是列表中最高的。要提取重复项,我会这样做:

val otherToppers = sortedPairsFirstAttr.tail.filter 
                   (e => e.attr1 == topper.attr1) // Expression(1)

这是关键点,恕我直言。在隔离顶部并在比较期间使用其属性 (attr1) 之前,我无法找到重复项。

// Then, I create a new list of the toppers only

val semiToppers = if (!otherToppers.empty) {
                        List(topper) ++ otherToppers // Expression(2)
                  }

然后,我对结果列表进行排序。根据attr2(Key_2)的值排序

val finalToppers = semiToppers.sortWith(_._2 < _.2) // Expression(3)

因此,实际上,我使用复合键对原始列表进行了排序:在 Key_1 和 然后 上按降序排序,在 Key_2 上按升序排序。

我了解Experssion(1) 可以针对长列表进行优化;我不需要遍历整个列表。我可以早点摆脱它。我也明白 Expression(2)Expression(3) 可以合并。所以,我们可以把这两点放在一边。

我的问题是我的方法在功能上是否合适并且可以接受。如果不是,那么您认为哪种方法更好、更惯用?

这是一个学习者的问题。因此,我全心全意地寻求您的 cmets/观察。

【问题讨论】:

  • 您的问题中的警告和您对答案的限制,几乎没有留下任何建议的余地。代码是专门构建的,也许你可以用一种能引出其目的的方式来重新表述这个问题。
  • @DaveSwartz,您能否指出我问题中的警告?我已准备好做任何有助于获得正确、适当、准确答案的事情!
  • 一个是“让我们假设它已经以一种有效的方式排序,因为这不是重点。”。另一个是:“我知道Expersion(1) 可以优化......”。您的问题应该在前面说明,直到帖子接近尾声才能解决您的问题:“如果我的方法在功能上合适且可以接受。我还建议通过提供更多上下文来留出更多建议空间。“如果不是,那么你认为什么是更好、更惯用的方法?”。这个问题也相当主观。建议你改用codereview.stackexchange.com
  • @DaveSwartz,我故意放了这两个(你引用的警告),以帮助他人,不花时间我知道。看来这并没有达到预期的效果。但是,我接受我可以将主要问题放在首位的观点。此外,我看到提出问题的方式可能会有所不同,尽管我必须在这里补充一点,过去我曾以类似的方式提出过关于 SO 的问题并得到了非常有用的答案。感谢您的建议。

标签: algorithm list scala sorting composite-key


【解决方案1】:

您的解决方案有效且有效,因此我不会对此发表评论。您已经使用了val 和不可变数据结构,这是纯粹的做法。 相反,我会建议一种替代方式,它短一些,您可能也会感兴趣:

既然您无论如何都要对列表进行预处理,我建议您首先对它进行排序lexicographically:首先按降序attr1,如果出现平局,则按升序attr2:

scala> val originalList = Seq((1,0), (2,7), (3,1), (1,3), (2,5), (3,4), (3,2))
scala> val lst = originalList.sortBy(x => (-x._1, x._2))
lst: Seq[(Int, Int)] = List((3,1), (3,2), (3,4), (2,5), (2,7), (1,0), (1,3))

现在您只需从前面取出重复项,结果已经按 attr2 排序:

scala> lst.takeWhile(_._1 == lst.head._1)
res8: Seq[(Int, Int)] = List((3,1), (3,2), (3,4))

【讨论】:

  • 除了您的 cmets 和建议之外,我也感谢您带领我了解更多关于 sortBy 以及 Ordering 其中元组的字段可用于定制排序!好东西。一个人每天都在学习! (不知道为什么你的名字前缀为'@'没有正确显示,我不是SO专家,抱歉)。
  • @Nirmalya 很高兴为您提供帮助。 Stack Overflow 让您不要通过 @ 与我联系,因为如果我的回答被评论,我会收到通知:P Stack Overflow 非常聪明。
猜你喜欢
  • 1970-01-01
  • 2019-06-19
  • 2021-12-04
  • 2019-03-09
  • 1970-01-01
  • 2021-12-07
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
相关资源
最近更新 更多