Scala - 匿名对象选择查询

时间:2017-04-03 11:43:50

标签: scala

我有一个原始的C#LINQ查询:

var rez = planes
    .Where(b => (b.FlDate >= dateFrom) && (b.FlDate <= dateTo))
    .GroupBy(i => i.Destination)
    .Select(g => new { Destination = g.Key, Count = g.Count() })
    .ToList();

并重新编写带有问题的Scala代码:

var rez = planes
  .filter( _.FlDate.getMillis >= dateFrom.getMillis)
  .filter(_.FlDate.getMillis <= dateTo.getMillis)
  .groupBy(_.Destination)
  .flatMap( new { Destination:String = _.Key, Count = _.Count() })//issue is here

所以主要任务是创建具有DestinationCount属性的匿名对象数组

Scala PlanesLogRow类来源:

import com.github.nscala_time.time.Imports._

class PlanesLogRow {
  var FlDate:DateTime = new DateTime
  var Origin = ""
  var Destination = ""
}

2 个答案:

答案 0 :(得分:4)

Scala中没有C#comaprable anonmyous类(虽然它们确实存在,但它们对IMO的作用却远没那么大)。或者,您可以使用具有良好语法糖的Tuple2[String, Int](String, Int))。

为了方便起见,我们可以创建case class的{​​{1}},它为我们提供了一种创建类的简洁方法(注意所有值都是不可变的):

PlanesLogRow

现在让我们创建一个序列:

case class PlanesLogRow(flightDate: ZonedDateTime, origin: String, destination: String)

从和到日期(为方便起见,我使用了val flights = Seq( PlanesLogRow(ZonedDateTime.now(), "US", "Kiev"), PlanesLogRow(ZonedDateTime.now().plusHours(2L), "US", "Prague"), PlanesLogRow(ZonedDateTime.now().plusHours(4L), "Canada", "Prague") ) ):

java.time

现在,我们可以过滤一次(不需要对集合进行两次传递),分组,然后将结果输出到val dateFrom = ZonedDateTime.now val dateTo = ZonedDateTime.now().plusHours(5L)

Map[String, Int]

收率:

val result: Map[String, Int] =
  flights
    .filter(logRow => logRow.flightDate.isAfter(dateFrom) && logRow.flightDate.isBefore(dateTo))
    .groupBy(_.destination)
    .map { case (location, logRows) => (location, logRows.length) }

在Scala中,与C#中的LINQ不同,集合上的组合是严格的,而不是懒惰的。这意味着对于您调用的每个组合子(Map(Prague -> 2) map等),将会分配一个新的集合。要解决这个问题,您可以使用生成惰性集合的views

filter

除此之外,scala字段的命名约定是camelCase,而不是像C#那样的PascalCase。

答案 1 :(得分:1)

作为@Yuval Itzchakov的优秀答案的补充,如果你真的想要AnyRef{val destination: String; val count: Int}而不是Tuple2[String, Int],你可以替换它的最后map与...:

.map {
  case (location, logRows) => new {
    val destination = location;
    val count = logRows.length
  }
}

注意:正如@pedrofurla正确指出的那样,此解决方案强制运行时使用反射。