Scala:添加序列号以复制列表中的元素

时间:2017-07-30 13:04:34

标签: scala collections

我有一个列表,想要添加序列号来复制元素。

val lst=List("a", "b", "c", "b", "c", "d", "b","a") 

结果应为

List("a___0", "b___0", "c____0", "b___1", "c____1", "d___0", "b___2","a___1")

保留原始订单。

到目前为止我所拥有的:

val lb=new ListBuffer[String]()
for(i<-0 to lst.length-2) {
  val lbSplit=lb.map(a=>a.split("____")(0)).distinct.toList
  if(!lbSplit.contains(lst(i))){
    var count=0
    lb+=lst(i)+"____"+count

    for(j<-i+1 to lst.length-1){
      if(lst(i).equalsIgnoreCase(lst(j))) {
        count+=1
        lb+= lst(i)+"____"+count
      }
    }
  }
}

导致:

res120: scala.collection.mutable.ListBuffer[String]
  = ListBuffer(a____0, a____1, b____0, b____1, b____2, c____0, c____1, d____0)
弄乱了订单。此外,如果有一个更简洁的方式,那将是伟大的。

2 个答案:

答案 0 :(得分:2)

这应该没有任何可变变量。

val lst=List("a", "b", "c", "b", "c", "d", "b","a")

lst.foldLeft((Map[String,Int]().withDefaultValue(0),List[String]())){
  case ((m, l), x) => (m + (x->(m(x)+1)), x + "__" + m(x) :: l)
}._2.reverse
// res0: List[String] = List(a__0, b__0, c__0, b__1, c__1, d__0, b__2, a__1)

<强>解释

  • lst.foldLeft - 获取List项目(在本例中为List[String])并将它们(从左侧开始)折叠为单个项目。
  • (Map[String,Int]().withDefaultValue(0),List[String]()) - 在这种情况下,新项目将是(Map[String,Int], List[String])类型的元组。我们将使用空Map和空List
  • 来启动元组
  • case ((m, l), x) => - 每次将lst中的元素传入元组计算时,我们都会调用该元素x。我们还将从之前的计算中收到元组。我们会致电Map部分m,我们会致电List部分l
  • m + (x->(m(x)+1)) - 新元组的Map部分是通过创建/更新此Stringx)的计数并将其添加到收到的{{}}来创建的。 {1}}。
  • Map - 新元组的x + "__" + m(x) :: l部分是通过预先审核新的List来创建的。
  • String - }._2.reverse已完成。从元组(第二个元素)中提取fold并反转它以恢复元素的原始顺序。

答案 1 :(得分:1)

我认为保留订单的更简洁的方法就是使用Map[String, Int]来保持每次看到特定字符串时的总计。然后,您可以直接映射lst,并在每次看到字符串时不断更新地图:

var map = Map[String, Int]()
lst.map { str =>
  val count = map.getOrElse(str, 0) //get current count if in the map, otherwise zero
  map += (str -> (count + 1)) //update the count
  str + "__" + count
}

将为您的示例提供以下内容:

List(a__0, b__0, c__0, b__1, c__1, d__0, b__2, a__1)

我认为最容易阅读,但如果你想避免var,那么你可以使用foldLeft和元组来保持地图的中间状态:

lst.foldLeft((List[String](), Map[String, Int]())) { case ((list, map), str) =>
  val count = map.getOrElse(str, 0)
  (list :+ (str + "__" + count), map + (str -> (count + 1)))
}._1