将自动递增后缀附加到列表的重复元素
Append auto-incrementing suffix to duplicated elements of a List
给定以下列表:
val l = List("A", "A", "C", "C", "B", "C")
如何为每个元素添加一个自动递增的后缀,以便我最终得到一个不再包含重复项的列表,如下所示(顺序无关紧要):
List("A0", "A1", "C0", "C1", "C2", "B0")
刚写完这道题就自己发现了
val l = List("A", "A", "C", "C", "B", "C")
l.groupBy(identity) // Map(A->List(A,A),C->List(C,C,C),B->List(B))
.values.flatMap(_.zipWithIndex) // List((A,0),(A,1),(C,0),(C,1),(C,2),(B,0))
.map{ case (str, i) => s"$str$i"}
如果有更好的解决方案(可能使用foldLeft
)请告诉我
也许不是最易读的解决方案,但是...
def appendCount(l: List[String]): List[String] = {
// Since we're doing zero-based counting, we need to use `getOrElse(e, -1) + 1`
// to indicate a first-time element count as 0.
val counts =
l.foldLeft(Map[String, Int]())((acc, e) =>
acc + (e -> (acc.getOrElse(e, -1) + 1))
)
val (appendedList, _) =
l.foldRight(List[String](), counts){ case (e, (li, m)) =>
// Prepend the element with its count to the accumulated list.
// Decrement that element's count within the map of element counts
(s"$e${m(e)}" :: li, m + (e -> (m(e) - 1)))
}
appendedList
}
这里的想法是为列表中的每个元素创建一个计数。然后,您从原始值列表的后面开始迭代,并在递减计数映射的同时将计数附加到该值。
您需要在这里定义一个助手,因为 foldRight
需要新的 List[String]
和计数作为累加器(因此,return 两者都需要)。您只需忽略最后的计数(无论如何它们都是 -1
)。
我想你的方法可能更清楚。如果这是一个问题,您需要进行基准测试以查看哪个更快。
以单程直截了当的方式:
def transformList(list : List[String]) : List[String] = {
val buf: mutable.Map[String, Int] = mutable.Map.empty
list.map {
x => {
val i = buf.getOrElseUpdate(x, 0)
val result = s"${x.toString}$i"
buf.put(x, i + 1)
result
}
}
}
transformList( List("A", "A", "C", "C", "B", "C"))
给定以下列表:
val l = List("A", "A", "C", "C", "B", "C")
如何为每个元素添加一个自动递增的后缀,以便我最终得到一个不再包含重复项的列表,如下所示(顺序无关紧要):
List("A0", "A1", "C0", "C1", "C2", "B0")
刚写完这道题就自己发现了
val l = List("A", "A", "C", "C", "B", "C")
l.groupBy(identity) // Map(A->List(A,A),C->List(C,C,C),B->List(B))
.values.flatMap(_.zipWithIndex) // List((A,0),(A,1),(C,0),(C,1),(C,2),(B,0))
.map{ case (str, i) => s"$str$i"}
如果有更好的解决方案(可能使用foldLeft
)请告诉我
也许不是最易读的解决方案,但是...
def appendCount(l: List[String]): List[String] = {
// Since we're doing zero-based counting, we need to use `getOrElse(e, -1) + 1`
// to indicate a first-time element count as 0.
val counts =
l.foldLeft(Map[String, Int]())((acc, e) =>
acc + (e -> (acc.getOrElse(e, -1) + 1))
)
val (appendedList, _) =
l.foldRight(List[String](), counts){ case (e, (li, m)) =>
// Prepend the element with its count to the accumulated list.
// Decrement that element's count within the map of element counts
(s"$e${m(e)}" :: li, m + (e -> (m(e) - 1)))
}
appendedList
}
这里的想法是为列表中的每个元素创建一个计数。然后,您从原始值列表的后面开始迭代,并在递减计数映射的同时将计数附加到该值。
您需要在这里定义一个助手,因为 foldRight
需要新的 List[String]
和计数作为累加器(因此,return 两者都需要)。您只需忽略最后的计数(无论如何它们都是 -1
)。
我想你的方法可能更清楚。如果这是一个问题,您需要进行基准测试以查看哪个更快。
以单程直截了当的方式:
def transformList(list : List[String]) : List[String] = {
val buf: mutable.Map[String, Int] = mutable.Map.empty
list.map {
x => {
val i = buf.getOrElseUpdate(x, 0)
val result = s"${x.toString}$i"
buf.put(x, i + 1)
result
}
}
}
transformList( List("A", "A", "C", "C", "B", "C"))