在scala我们如何找到每个客户的最新记录?

时间:2016-08-11 12:08:25

标签: scala

我的输入文件如下。它包含每个客户的一些购买详细信息。

输入:

 100,Surender,2015-01-23,PHONE,20000
 100,Surender,2015-01-24,LAPTOP,25000
 101,Ajay,2015-02-21,LAPTOP,40000
 101,Ajay,2015-03-10,MUSIC_SYSTEM,50000
 102,Vikram,2015-07-20,WATCH,60000

我的要求是我想了解每位客户的最新购买详情。

所以预期的输出是

预期OutPut:

List(101,Ajay,2015-03-10,MUSIC_SYSTEM,50000)
List(100,Surender,2015-01-24,LAPTOP,25000)
List(102,Vikram,2015-07-20,WATCH,60000)

我尝试了下面的代码,它给了我预期的输出..

但是这下面的逻辑有点类似于java。

我的Scala代码:

 package pack1
 import scala.io.Source
 import scala.collection.mutable.ListBuffer
 object LatestObj {

 def main(args:Array[String])=
 {
    var maxDate ="0001-01-01"
    var actualData:List[String] =List()
    var resultData:ListBuffer[String] = ListBuffer()

    val myList=Source.fromFile("D:\\Scala_inputfiles\\records.txt").getLines().toList;
    val myGrped = myList.groupBy { x => x.substring(0,3) }
//println(myGrped)
     for(mappedIterator <- myGrped)
       {
         // println(mappedIterator._2)
            actualData =mappedIterator._2
            maxDate=findMaxDate(actualData)
            println( actualData.filter { x => x.contains(maxDate) })
       }


 }

   def findMaxDate( mytempList:List[String]):String =
   {
         var maxDate ="0001-01-01"
            for(m <- mytempList)
              {
                var transDate= m.split(",")(2)
                if(transDate > maxDate)
                {
                    maxDate =transDate
                }
     }

  return maxDate
  }

   }

有人可以帮助我使用scala以更简单的方式尝试相同的方法吗?

或者上面的代码是实现该逻辑的唯一方法吗?

2 个答案:

答案 0 :(得分:2)

这是一个使用groupByreduce的简单版本,另外还有一个方便的案例类来优雅地表示记录:

case class Record(id: Int, username: String, date: Date, product: String, cost: Double)

val dateFormat: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd")
val stringList = Source.fromFile("./records.txt").getLines().toList

// split by comma and parse into case class - while REMOVING bad records
val records = stringList.map(_.split(",")).collect {
  case Array(id, username, date, product, cost) => Record(id.toInt, username, dateFormat.parse(date), product, cost.toDouble)
}

// group by key, and reduce each group to latest record
val result = records.groupBy(_.id).map { _._2.reduce {
  (r1: Record, r2: Record) => if (r1.date.after(r2.date)) r1 else r2
}}

result.foreach(println)
// prints:
// Record(101,Ajay,Tue Mar 10 00:00:00 IST 2015,MUSIC_SYSTEM,50000.0)
// Record(100,Surender,Sat Jan 24 00:00:00 IST 2015,LAPTOP,25000.0)
// Record(102,Vikram,Mon Jul 20 00:00:00 IDT 2015,WATCH,60000.0)

请注意,此实现不会使用 mutable 变量或集合,这通常会显着简化代码,并且对于像Scala这样的函数式语言来说更加惯用。

答案 1 :(得分:1)

甚至更简单的版本,也使用巧合相同名称的案例类。但是,不会像Tzach那样删除不良记录,而是将所有内容保留为字符串。

case class Record(id: String, name: String, dateString: String, item: String, count: String)
  myList.map { line =>
    val Array(id, name, dateString, item, count) = line.split(",")
    Record(id, name, dateString, item, count)
  }
  .groupBy(_.id)
  .map(_._2.maxBy(_.dateString))
  .toList