Scala оптимизация с учетом регистра для повышения производительности и читабельности - PullRequest
0 голосов
/ 23 января 2020

Я написал ниже для сопоставления с образцом в scala:

scala> val rowMap = Map("abc" -> null)
rowMap: scala.collection.immutable.Map[String,Null] = Map(abc -> null)

scala> val postgresKey = "abc"
postgresKey: String = abc

scala> val h2Key = "xyz"
h2Key: String = xyz

Предлагаемый вариант:

scala> (rowMap.get(postgresKey).map(_.asInstanceOf[String]) , rowMap.get(h2Key).map(_.asInstanceOf[String])) match
     |       {
     |         case (Some(value), _) if (value != null && value.trim.nonEmpty) => value
     |         case (None, Some(value)) if (value != null && value.trim.nonEmpty) => value
     |         case (_ , _) => "0.0"
     |       }
res9: String = 0.0

Мой код:

scala> (rowMap.get(postgresKey).map(_.asInstanceOf[String]) , rowMap.get(h2Key).map(_.asInstanceOf[String])) match
     |       {
     |         case (Some(value), _) if (value != null ) => if (value.trim.nonEmpty) value else "0.0"
     |         case (None, Some(value)) if (value != null ) => if (value.trim.nonEmpty) value else "0.0"
     |         case (_ , _) => "0.0"
     |       }  
res10: String = 0.0

Предлагаемый вариант имеет какие-либо преимущества в производительности, чем мой код. Я знаю, что && перестанет сравнивать value.trim.nonEmpty в тот момент, когда он увидит null. Итак, мы экономим на 1 сравнении.

Я понимаю, что читать также чище. Что-нибудь еще, что лучше в предлагаемом подходе?

РЕДАКТИРОВАТЬ 1: мне сказали избегать использования null. Тем не менее, это поступает мне от анорма defaultParser. Поскольку сценарий сложно воспроизвести, я привел пример выше. В моем случае модульные тесты проводятся во второй половине дня, а фактическая база данных - postgres.

Ниже приведен фрагмент кода:

            val anormQuery = SQL(query)
            // map the anorm Row as per the input params, differentiate into aggregated and group cols
            val tmp = anormQuery.as(anormQuery.defaultParser.*)

            logger.info(" Printing the result set object " + tmp.toString())

            val finalSqlResultset = tmp.map(row ⇒ {

              // Anorm row.asMap has this behaviour that it adds either a leading dot(.) or <tablename>. in front of the map keys (the columns/alias in sql) based on whether it is H2 or Postgres

              val rowMap = for ((k, v) ← row.asMap) yield (k, v)
              logger.info("Print the resultSet as map : " + rowMap.toString())


              val aggregates = expressionsToAggregate.map(input ⇒ {
                val (anormKey, postgresKey) = doesColumnHaveAlias.get(input.alias.getOrElse("UnknownAlias")).getOrElse(("Unknown", "Unknown"))
                //
                val aggResult = AggregatedValue(
                  input.alias.get,
                  (rowMap.get(postgresKey).map(_.asInstanceOf[String]), rowMap.get(anormKey).map(_.asInstanceOf[String])) match {
                    case (Some(value), _) if (value != null && value.trim.nonEmpty) ⇒ value
                    case (None, Some(value)) if (value != null && value.trim.nonEmpty) ⇒ value
                    case (_, _) ⇒ "0.0"
                  })
                logger.info("## TRACE 1 ##" + aggResult)
                aggResult
              })
})

1 Ответ

4 голосов
/ 23 января 2020

Прежде всего, не использует нули . Когда-либо. Просто сделайте val rowMap = Map("abc" -> "").

Или, что еще лучше, просто не помещайте мусор в карту вообще (вы все равно его фильтруете!).

Во-вторых, поскольку вы упомянули читабельность, похоже, вы ищете что-то вроде этого:

 rowMap.get(postgresKey).filterNot(_.trim.isEmpty)
  .orElse(rowMap.get(h2Key).filerNot(_.trim.isEmpty))
  .getOrElse("0.0")

Наконец, чтобы ответить на ваш вопрос, две версии, которые вы показали, не эквивалентны. Первый делает то, что я делал выше. Второй:

 rowMap.get(postgresKey).orElse(rowMap.get(h2Key))
   .filterNot(_.trim.isEmpty)
   .getOrElse("0.0")

В первом случае установка postgresKey на "" равносильна тому, что он вообще не устанавливается, вы всегда получите значение для h2Key в этом дело. В последнем случае, если postgresKey установлен на "", вы получите «0.0», независимо от того, что установлено h2Key.

Итак, поведение отличается, оно зависит от того, какое из них вам действительно нужно.

Если вам нужен первый тип поведения, его также можно написать так:

Some(rowMap.filterValues(_.trim.nonEmpty)).flatMap { case m => 
   m.get(postrgesKey) orElse m.get(h2Key)
}.getOrElse("0.0")

Или, если вы послушаете мой совет и решите не помещать мусор на карту, вы также можете потерять фильтр:

roMap.get(postrgesKey) orElse rowMap.get(h2Key) getOrElse "0.0"
...