有条件地使用.reverse与Scala在同一行

时间:2018-02-14 18:17:42

标签: scala combinators

我在Scala中有一个组合子组合,最后一个是.top,我可以将其用作.top(num)(Ordering[(Int, Int)].reverse),具体取决于布尔参数。

如何根据布尔参数在同一行中实现组合使用或不使用.reverse组合?我的意思是,没有创建另一个val来表明是否使用.reverse

val mostPopularHero = sparkContext
  .textFile("resource/marvel/Marvel-graph.txt") // build up superhero co-apperance data
  .map(countCoOccurrences) // convert to (hero ID, number of connections) RDD
  .reduceByKey((x, y) => x + y) // combine entries that span more than one line
  .map(x => (x._2, x._1)) // flip it from (hero ID, number of connections) to (number of connections, hero ID)
  .top(num)(Ordering[(Int, Int)].reverse)

2 个答案:

答案 0 :(得分:2)

解决方案0

正如 nicodp 已经指出的那样,如果你在范围内有一个布尔变量b,你可以简单地替换表达式

Ordering[(Int, Int)]

通过if - 表达式

if (b) Ordering[(Int, Int)] else Ordering[(Int, Int)].reverse

我必须承认,这是我能想到的最短,最清晰的解决方案。

但是......我不太喜欢表达式Ordering[(Int, Int)]出现在代码中两次。在这种情况下,它并不重要,因为它很简短,但如果表达式稍微长一点怎么办?显然,即使是Ruby has something for such cases

所以,我尝试了一些不重复子表达式Ordering[(Int, Int)]的方法。最好的解决方案是,如果我们在标准库中有一个默认的Id - monad实现,那么我们可以简单地将一个值包装在pure中,然后使用布尔值map 。 但标准库中没有Id。因此,这里有一些其他提案,仅针对有问题的表达式变得更长的情况:

解决方案1 ​​

您可以在scala中使用块作为表达式,因此您可以替换上面的内容 Ordering[(Int, Int)]

{val x = Ordering[(Int, Int)]; if (b) x else x.reverse}

更新:等等!这比重复的版本短! ;)

解决方案2

定义有条件地反转排序的函数,声明Ordering[(Int, Int)]作为参数的类型,然后 而不是重新键入Ordering[(Int, Int)]作为表达式,请使用implicitly

((x: Ordering[(Int, Int)]) => if (b) x else x.reverse)(implicitly)

解决方案3

我们没有Id,但我们可以滥用其他仿函数的构造函数和消除器。例如,可以将复杂表达式包装在ListOption中,然后map,然后解压缩结果。以下是Some的变体:

Some(Ordering[(Int, Int)]).map{ x => if(b) x else x.reverse }.get

理想情况下,这应该是Id而不是Some。请注意,解决方案1执行与默认环境monad类似的操作。

解决方案4

最后,如果您的代码中出现上述模式不止一次,那么引入一些额外的语法来处理它可能是值得的:

implicit class ReversableOrderingOps[X](ord: Ordering[X]) {
  def reversedIf(b: Boolean): Ordering[X] = if (b) ord.reverse else ord
}

现在你可以定义这样的排序:

val myConditionHolds = true
val myOrd = Ordering[(Int, Int)] reversedIf myConditionHolds

或直接在你的冗长表达中使用它:

val mostPopularHero = sparkContext
  .textFile("resource/marvel/Marvel-graph.txt")
  .map(countCoOccurrences)
  .reduceByKey((x, y) => x + y)
  .map(x => (x._2, x._1))
  .top(num)(Ordering[(Int, Int)] reversedIf myConditionHolds)

答案 1 :(得分:1)

我不太确定你是否可以访问布尔参数,但你可以按照以下方式解决这个问题:

 .top(num)(if (booleanParameter) Ordering[(Int, Int)].reverse else Ordering[(Int, Int)])