Scala - 如何从原始数据创建映射以计算不同的值

时间:2014-07-16 05:44:21

标签: scala

Scala新手并尝试读取输入原始数据,以便在多个字段上生成包含groupBy的地图。

示例原始数据:

date,uid,site,success
2014-07-14,userA,google,1
2014-07-14,userB,google,1
2014-07-14,userC,yahoo,1
2014-07-14,userD,facebook,1

我想报告每个日期的每个网站的不同用户数,即

2014-07-14,google,2
2014-07-14,yahoo,1
2014-07-14,facebook,1

为此,我试图在日期和站点字段上使用groupBy,其值为uid。一旦我有了这个数据结构,我就可以迭代地图并计算不同的地图值。 谁能指出我如何生成数据结构?

谢谢!

3 个答案:

答案 0 :(得分:2)

我希望我能正确理解你。这是一个完整的例子。

case class Data(date: String, uid: String, site: String, success: Int)

val sampleData = List(
  Data("2014-07-14","userA","google",1),
  Data("2014-07-14","userA","google",1),
  Data("2014-07-14","userB","google",1),
  Data("2014-07-14","userC","yahoo",1),
  Data("2014-07-14","userD","facebook",1)
)

sampleData.groupBy(_.date).map
  {case (date, datelist) => (date, datelist.groupBy(_.site).map
    {case (site, sitelist) => (site, sitelist.groupBy(_.uid).size)})}

输出为:Map(2014-07-14 -> Map(google -> 2, yahoo -> 1, facebook -> 1))

基本上,您会获得每个日期的地图,其中包含来自不同用户的网站访问权限。请注意,userA的2次访问计为1。

 sitelist.groupBy(_.uid).size

uid计算不同的访问次数。

编辑是的,没有额外的数据结构是可能的。你现在必须处理数组的索引。

val fileText = """2014-07-14,userA,google,1
  2014-07-14,userA,google,1
  2014-07-14,userA,google,1
  2014-07-14,userB,google,1
  2014-07-14,userC,yahoo,1
  2014-07-14,userD,facebook,1""".stripMargin

fileText.lines.map(_.split(",")).toList.groupBy(_(0)).map
  {case (date, datelist) => (date, datelist.groupBy(_(2)).map
    {case (site, sitelist) => (site, sitelist.groupBy(_(1)).size)})}

答案 1 :(得分:1)

为清楚起见,丢弃标题行,可能的实现如下:

val text = """2014-07-14,userA,google,1
            |2014-07-14,userA,google,1
            |2014-07-14,userB,google,1
            |2014-07-14,userC,yahoo,1
            |2014-07-16,userC,yahoo,1
            |2014-07-14,userD,facebook,1
            |2014-07-14,userE,facebook,1
            |""".stripMargin

val uniqueUsersByDateSite: Map[(String, String), Int] = text.lines.map {
  line =>
    val tokens = line.split(",")
    (tokens(0), tokens(1), tokens(2))
}.toSet.groupBy {
  tuple: (String, String, String) =>
    (tuple._1, tuple._3)
}.mapValues {
  _.size
}

通过创建一组元组(date, uid, site),我们会为特定日期的网站的每个唯一身份用户收集一个项目。

groupBy方法然后按(date, site)收集,将同一日期和网站的N个项目转换为地图条目,其中包含与相应日期的唯一身份用户数相对应的多个项目站点。

最终的mapValue方法可以达到预期的效果:

Map((2014-07-16,yahoo) -> 1, (2014-07-14,facebook) -> 2, (2014-07-14,google) -> 2, (2014-07-14,yahoo) -> 1)

答案 2 :(得分:0)

回答贴@Kigyo似乎很不错,但我认为你可以延长一点: 所以,假设这个数据结构:

case class Data(date: String, uid: String, site: String, success: Int)
val sampleData = List(
  Data("2014-07-14","userA","google",1),
  Data("2014-07-14","userA","google",1),
  Data("2014-07-14","userB","google",1),
  Data("2014-07-14","userC","yahoo",1),
  Data("2014-07-14","userD","facebook",1)
)

你可以通过以下方式实现目标:

list.groupBy((_.date , _.site)).collect{ case (a , b : List[Data]) =>(a._1 , a._2 , b.map(_.success).sum) } ;

返回一个Tuple3列表,就像你想要的那样