Скала-фу Java-функцию? - PullRequest
       3

Скала-фу Java-функцию?

2 голосов
/ 18 февраля 2011

Я недавно переключил свое назначение с Java на Scala. Тем не менее, это все еще выглядит как Java. Например, приведенная ниже функция выполняет поиск в дереве диапазонов, а внутри я делаю несколько проверок «isInstanceOf».

Однако - замена их на «матч» кажется, что это заняло бы только больше места. Кто-нибудь может предложить некоторые улучшения, как "масштабировать" этот код?

def rangeSearch2D(treeRoot: Node, lower: Data2D, upper: Data2D, 
         visited: Visited): Seq[Data2D] = {

    if (treeRoot == null) {
      // return empty list
  return Vector()
}
// increment visit count
if (visited != null)
  visited.visit2D(treeRoot)

var results = ArrayBuffer[Data2D]()

// Find nearest common ancestor with value between lower.x and upper.x
var common: Node = commonAncestor(treeRoot, lower, upper, visited)

if (common.isInstanceOf[LeafNode]) {
  return Vector(common.asInstanceOf[LeafNode].data)
}

/** Common non-leaf node, must process subtree */
/** Process left subtree */
var current = common.left

while (!current.isInstanceOf[LeafNode]) {
  if (visited != null)
    visited.visit2D(current)

  //Find a path from current to lower.x
  if (lower.x <= current.midRange) {
    results.appendAll(rangeSearch1D(current.right.subTree, 
                        lower, upper, visited))
    current = current.left
  } else {
    current = current.right
  }
}
//Check if current leaf node is in range
if (inRange(current, lower, upper)) {

  results.append(current.asInstanceOf[LeafNode].data)
}
/** Process right subtree */
current = common.right

while (!current.isInstanceOf[LeafNode]) {
  if (visited != null)
    visited.visit2D(current)

  //Find a path from current to upper.x
  if (upper.x >= current.midRange) {

    results.appendAll(rangeSearch1D(current.left.subTree, 
                        lower, upper, visited))
    current = current.right
  } else {
    current = current.left
  }
}
//Check if current leaf node is in range
    if (inRange(current, lower, upper)) {
      results.append(current.asInstanceOf[LeafNode].data)
    }

    return results
  }

Ответы [ 3 ]

5 голосов
/ 18 февраля 2011

Ну, во-первых, вы можете избавиться от null, заменив параметры, которые могут быть null на Option.В коде вы затем меняете

if (visited != null)
  visited.visit2D(x)

на

visited foreach (_ visit2D x)

Оба цикла while можно заменить рекурсивными функциями.Вместо добавления результата в изменяемую переменную, вы можете передать его в качестве неизменяемого параметра-накопителя в рекурсивной функции.

Если у Node есть экстрактор, вы можете использовать защиту регистра, чтобы сделать midrangeтестовое задание.Не добавляет много, но более идиоматично.

У меня такое ощущение, что оба цикла while могут быть объединены в одну рекурсию, но я не рассмотрел алгоритм достаточно, чтобы определиться с этим.Если это так, вы можете избежать раннего возврата common.

Кстати, здесь есть ошибка, поскольку в пределах диапазона может отсутствовать общий предок.

3 голосов
/ 18 февраля 2011

Для Scala-фэй кода выше есть несколько довольно общих шагов, которые вы можете предпринять:

  • Уменьшите количество if операторов и замените приведение и типовые испытания с сопоставлением с образцом

  • Устранить , в то время как заявления с рекурсивные функции / методы или методы библиотеки (такие как сгибы)

  • Устранить переменные путем прохождения аккумуляторы в функцию / метод вызывает и присваивает результат для восстановления окончательного накопления

  • Сокращение назначений с помощью значений возвращается многоблочными операторами, такими как , если и try catch

  • Устранить нули, используя Опция Типы

  • Исключить ключевое слово return для охраны против отсутствующих перестановок

  • Не указывать блок / оператор else только в том случае, если он выполняет No-Op (компилятор должен ловить прерванные назначения из , если без else )

  • Используйте экстракторы, если это возможно, для простого разложения иерархий в сопоставлениях с образцами.

  • Если код плохо читается, рефакторинг и введение хорошо названных вспомогательных функций / методов

2 голосов
/ 18 февраля 2011

Первым шагом может быть что-то вроде этого, но я уверен, что есть больше возможностей (например, разбить метод на более мелкие шаги [и избегать таких вещей, как currentN этим), найти способ объединить loop0 и loop1, которые уродливы, заменяя ArrayBuffer неизменной структурой, делая посещение Option).

  def rangeSearch2D(treeRoot: Node, lower: Data2D, upper: Data2D, visited: Visited): Seq[Data2D] = 
  if (treeRoot == null) Vector() // return empty list
  else {

    // increment visit count
    if (visited != null)
      visited.visit2D(treeRoot)

    val results = ArrayBuffer[Data2D]()

    // Find nearest common ancestor with value between lower.x and upper.x
    val (current0,current2) = commonAncestor(treeRoot, lower, upper, visited) match {
      case leafNode:LeafNode => return Vector(leafNode.data)
      case common => (common.left, common.right)
    }     

    def loop0(current: Node):Node = current match {
      case _:LeafNode => current
      case _ =>  if (visited != null) visited.visit2D(current)
        if (lower.x <= current.midRange) {
          results.appendAll(rangeSearch1D(current.right.subTree, 
                                          lower, upper, visited))
          current.left
        } else current.right
    }

    val current1 = loop0(current0)


    //Check if current leaf node is in range
    if (inRange(current1, lower, upper))  results.append(current1.asInstanceOf[LeafNode].data)

    def loop1(current: Node):Node = current match {
      case _:LeafNode => current
      case _ =>  if (visited != null) visited.visit2D(current)
        if (upper.x >= current.midRange) {
          results.appendAll(rangeSearch1D(current.left.subTree, 
                                          lower, upper, visited))
          current.right
        } else current.left
    }

    val current3 = loop1(current2)

    //Check if current leaf node is in range
    if (inRange(current3, lower, upper)) 
      results.append(current3.asInstanceOf[LeafNode].data)

    results
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...