scala collections:映射列表并携带一些状态? [英] scala collections : map a list and carry some state?

查看:64
本文介绍了scala collections:映射列表并携带一些状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎一直都在遇到这个问题。我想修改列表中的某些元素,但是在执行操作时需要保持一些状态,因此map无法正常工作。

I seem to run into this problem all the time. I want to modify some of the elements in a list, but I need to keep some state as I do it, so map doesn't work.

这里是一个示例:

scala> val l1 = List("a","b","c","d","e","f","b","c","e","b","a")
l1: List[String] = List(a, b, c, d, e, f, b, c, e, b, a)

我想更改任何重复项的名称。所以我想结束这个:

I want to change the name of any duplicates. so I want to end up with this:

List(a1, b1, c1, d, e1, f, b2, c2, e2, b3, a2)

获取骗子很容易:

scala> val d = l1.diff(l1.distinct).distinct
d: List[String] = List(b, c, e, a)

现在我被卡住了。我通过将d转换为带有计数的HashMap并编写函数以遍历l1并对其进行更新来使其工作。递归之前的哈希值。

Now I'm stuck. I made it work by converting d to a HashMap w/ a count, and writing a function to iterate over l1 and update it & the hash before recursing. Which works fine, but looks kinda ugly to me.

但是我一直认为应该有一种方法可以处理集合类。

But I've always thought there should be a way to do w/ the collection classes.

这是我不喜欢的解决方案的其余部分:

Here is the rest of my solution which I don't like :

  val m = d.map( _ -> 1).toMap

  def makeIt(ms: Map[String, Int], ol: Iterator[String], res: List[String]=List[String]()) :List[String] = {
    if( !ol.hasNext) return res
    val no = ol.next()
    val (p,nm) = ms.get(no) match {
      case Some(v) => (s"$no$v", ms.updated(no,v+1))
      case None => (no,ms)
    }

    makeIt(nm,ol,res :+ p)
  }

  makeIt(m,l1.iterator)

哪个给了我我想要的东西

Which gives me what I want

res2: List[String] = List(a1, b1, c1, d, e1, f, b2, c2, e2, b3, a2)

我觉得我想在 mapWithState中传递一些信息。像折纸一样。也许它存在而我还没有找到?

I feel like I want "mapWithState" where I can just pass something along. Like Fold-ish. Maybe it exists and I just haven't found it yet?

谢谢

------ -UPDATE ---------

-------UPDATE---------

@Aluan Haddad的评论向我指出了这一方向。这会破坏秩序,这对我的情况很好。但是状态由zipWithIndex携带。我正在寻找一种更一般的情况,即状态需要在每个元素上进行一些计算。但是对于这种简单的情况,我喜欢它:

@Aluan Haddad's comment pointed me in this direction. Which destroys order, which is fine for my case. But the "state" is carried by zipWithIndex. I'm looking for a more general case where the state would require some computation at each element. But for this simple case I like it :

l1.groupBy(x=>x).values.flatMap( v =>{
    if( v.length <= 1 ) v else {
      v.zipWithIndex.map{ case (s,i) => s"$s${i+1}"}
    }
  })
res7: Iterable[String] = List(e1, e2, f, a1, a2, b1, b2, b3, c1, c2, d)


推荐答案

棘手的部分是 d f 元素没有任何修改。

The tricky part is that the "d" and "f" elements get no modification.

这就是我来的跟上。

This is what I came up with. It's a bit more concise, code wise, but does involve multiple traversals.

val l1: List[String] = List("a","b","c","d","e","f","b","c","e","b","a")

l1.reverse.tails.foldLeft(List[String]()){
  case (res, Nil) => res
  case (res, hd::tl) =>
    val count = tl.count(_ == hd)
    if (count > 0) s"$hd${count+1}" +: res
    else if (res.contains(hd+2)) (hd+1) +: res
    else hd +: res
}
//res0: List[String] = List(a1, b1, c1, d, e1, f, b2, c2, e2, b3, a2)

通过使用 tails ,每个元素 hd ,都能看到未来, tl ,以及过去的 res

By using tails, each element, hd, is able to see the future, tl, and the past, res.

这篇关于scala collections:映射列表并携带一些状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆