我有一个列表,想要添加序列号来复制元素。
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)
弄乱了订单。此外,如果有一个更简洁的方式,那将是伟大的。
答案 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
部分是通过创建/更新此String
(x
)的计数并将其添加到收到的{{}}来创建的。 {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