List 列表中循环替换的Scala

List 列表中循环替换的Scala,list,scala,type-mismatch,List,Scala,Type Mismatch,也许这很容易解决,但你能帮我解决或指导我找到解决方案吗。我有一个remove函数,它遍历一个元组列表“List[(String,Any)],我试图在循环列表时用Nil替换值的1索引 但是当我尝试用Nil替换当前的v时,它说v被分配给“val”。现在我明白了scala列表是不可变的。也许这就是问题所在 我也尝试了尾部递归实现,但当我退出def时,类型不匹配。ie:是单位,但必需:选项[任何] // remove(k) removes one value v associated with key

也许这很容易解决,但你能帮我解决或指导我找到解决方案吗。我有一个remove函数,它遍历一个元组列表“List[(String,Any)],我试图在循环列表时用Nil替换值的1索引

但是当我尝试用Nil替换当前的v时,它说v被分配给“val”。现在我明白了scala列表是不可变的。也许这就是问题所在

我也尝试了尾部递归实现,但当我退出def时,类型不匹配。ie:是单位,但必需:选项[任何]

// remove(k) removes one value v associated with key k
// from the dictionary, if any, and returns it as Some(v).  
// It returns None if k is associated to no value.  
def remove(key:String):Option[Any] = {
    for((k,v) <- d){
        if(k == key){
            var temp:Option[Any] = Some(v)
            v = Nil
            return temp
        } 
    }; None
}

有什么建议吗?这是一个针对学校的家庭作业/项目,我想我可以为那些不喜欢帮助做家庭作业的人补充一下。

嗯,有很多方法可以回答这个问题。我将在这里用我自己的实现概述我能想到的那些,但是列表并不是详尽无遗的(也可能不是最优的实现)

首先,您可以尝试使用现有的组合器-常见的可疑对象是
map
flatMap
foldLeft
foldRight

def remove_flatMap(key: String, list: List[(String, Any)]): List[(String, Any)] =
  // The Java developer in me rebels against creating that many "useless" instances.
  list.flatMap {a => if(a._1 == key) Nil else List(a)}

def remove_foldLeft(key: String, list: List[(String, Any)]): List[(String, Any)] =
  list.foldLeft(List[(String, Any)]()) {(acc, a) =>
    if(a._1 == key) acc
    else            a :: acc
  // Note the call to reverse here.
  }.reverse

// This is more obviously correct than the foldLeft version, but is not tail-recursive.
def remove_foldRight(key: String, list: List[(String, Any)]): List[(String, Any)] =
  list.foldRight(List[(String, Any)]()) {(a, acc) =>
    if(a._1 == key) acc
    else            a :: acc
  }
问题是,据我所知,一旦达到某个条件,您就无法阻止它们:我认为它们不会直接解决您的问题,因为它们会删除
key
的所有实例,而不是第一个实例

您还需要注意:

  • foldLeft
    一旦完成,就必须反转列表,因为它以“错误”的顺序追加元素
  • foldRight
    没有该缺陷,但不是尾部递归的:它会导致大型列表出现内存问题
  • map
    不能用于解决您的问题,因为它只允许我们修改列表的值,而不允许修改列表的结构
您还可以使用自己的实现。我已经包括了两个版本,一个是尾部递归的,另一个不是。尾部递归的显然是更好的,但也更详细(我指责使用
List[(String,Any)]
而不是
Map[String,Any]
的丑陋之处:

def remove_nonTailRec(key: String, list: List[(String, Any)]): List[(String, Any)] = list match {
  case h :: t if h._1 == key => t
  // This line is the reason our function is not tail-recursive.
  case h :: t                => h :: remove_nonTailRec(key, t)
  case Nil                   => Nil
}

def remove_tailRec(key: String, list: List[(String, Any)]): List[(String, Any)] = {
  @scala.annotation.tailrec
  def run(list: List[(String, Any)], acc: List[(String, Any)]): List[(String, Any)] = list match {
    // We've been aggregating in the "wrong" order again...
    case h :: t if h._1 == key => acc.reverse ::: t
    case h :: t                => run(t, h :: acc)
    case Nil                   => acc.reverse
  }

  run(list, Nil)
}

当然,更好的解决方案是对作业使用正确的工具:a
Map[String,Any]


请注意,我认为我没有完全回答您的问题:我的示例删除了
,而您希望将其设置为
Nil
。由于这是您的家庭作业,我将让您了解如何更改我的代码以符合您的要求。

如果任何键只存在一次,则列表
是错误的集合。您应该使用
Map[String,Any]
。和列表

  • 您必须做额外的工作以防止重复条目
  • 检索键的速度越慢,列表越低。尝试检索不存在的键的速度将与列表的大小成比例
  • 我想第2点可能就是为什么您试图用
    Nil
    替换它,而不仅仅是从列表中删除密钥。
    Nil
    在这里使用是不正确的,真的。如果您尝试检索一个不存在的密钥,与已删除的密钥相比,您会得到不同的东西。这真的是您想要的吗?返回
    Some(Nil)
    有多大意义

    这里有两种方法可以处理可变或不可变列表,但不能假设您成功地阻止了重复项的出现

    val l1: List[(String, Any)] = List(("apple", 1), ("pear", "violin"), ("banana", Unit))
    val l2: List[(Int, Any)] = List((3, 1), (4, "violin"), (7, Unit))
    
    def remove[A,B](key: A, xs: List[(A,B)]) = (
      xs collect { case x if x._1 == key => x._2 }, 
        xs map { case x if x._1 != key => x; case _ => (key, Nil) }
    )
    
    scala>  remove("apple", l1)
    res0: (List[(String, Any)], List[(String, Any)]) = (List((1)),List((apple, List()),(pear,violin), (banana,object scala.Unit)))
    
    scala> remove(4, l2)
    res1: (List[(Int, Any)], List[(Int, Any)]) = (List((violin)),List((3,1), (4, List()), (7,object scala.Unit)))
    
    scala> remove("snark", l1)
    res2: (List[Any], List[(String, Any)]) = (List(),List((apple,1), (pear,violin), (banana,object scala.Unit)))
    
    它返回一个匹配值列表(如果不匹配,则返回一个空列表,而不是
    None
    )和元组中的剩余列表。如果您想要一个完全删除不需要的键的版本,请执行此操作

    def remove[A,B](key: A, xs: List[(A,B)]) = (
      xs collect { case x if x._1 == key => x._2 }, 
      xs filter { _._1 != key }
    )
    
    但也要看看这个:

    scala> l1 groupBy {
             case (k, _) if k == "apple" => "removed",
             case _ => "kept"
           }
    res3: scala.collection.immutable.Map[String,List[(String, Any)]] = Map(removed -> List((apple,1)), kept -> List((pear,violin), (banana,object scala.Unit)))
    
    这是你可以开发一点的东西。你所需要做的就是将
    (“apple”,Nil)
    添加到“keeped”列表中,并从“removed”列表中提取值

    请注意,我使用的是列表组合函数,而不是编写自己的递归代码;这通常会使代码更清晰,并且通常与手动递归函数一样快或更快

    另外请注意,我没有更改原始列表。这意味着我的函数同时处理可变列表和不可变列表。如果您有可变列表,请随意将我返回的列表指定为可变
    var
    。Win,Win的新值

    但请用地图来说明这一点。看看事情变得多么简单:

    val m1: Map[String, Any] = Map(("apple", 1), ("pear", "violin"), ("banana", Unit))
    val m2: Map[Int, Any] = Map((3, 1), (4, "violin"), (7, Unit))
    
    def remove[A,B](key: A, m: Map[A,B]) = (m.get(key), m - key)
    
    scala> remove("apple", m1)
    res0: (Option[Any], scala.collection.immutable.Map[String,Any]) = (Some(1),Map(pear -> violin, banana -> object scala.Unit))
    
    scala> remove(4, m2)
    res1: (Option[Any], scala.collection.immutable.Map[Int,Any]) = (Some(violin),Map(3 -> 1, 7 -> object scala.Unit))
    
    scala> remove("snark", m1)
    res2: res26: (Option[Any], scala.collection.immutable.Map[String,Any]) = (None,Map(apple -> 1, pear -> violin, banana -> object scala.Unit))
    

    combinator函数使事情变得更简单,但是当您使用正确的集合时,它变得非常简单,以至于编写一个特殊函数几乎不值得。当然,除非您试图隐藏数据结构——在这种情况下,您真的应该将其隐藏在一个对象中。

    注意,在注释中它说函数应该“从字典中删除与键相关联的值”,然后使用“代码>列表。也许您应该考虑<代码> map < /代码>,这样代码与意图:+)+ 1。您可能会发现我最近写的博客帖子是一个有益的补充,以理解@尼科拉斯努多的建议:
    val m1: Map[String, Any] = Map(("apple", 1), ("pear", "violin"), ("banana", Unit))
    val m2: Map[Int, Any] = Map((3, 1), (4, "violin"), (7, Unit))
    
    def remove[A,B](key: A, m: Map[A,B]) = (m.get(key), m - key)
    
    scala> remove("apple", m1)
    res0: (Option[Any], scala.collection.immutable.Map[String,Any]) = (Some(1),Map(pear -> violin, banana -> object scala.Unit))
    
    scala> remove(4, m2)
    res1: (Option[Any], scala.collection.immutable.Map[Int,Any]) = (Some(violin),Map(3 -> 1, 7 -> object scala.Unit))
    
    scala> remove("snark", m1)
    res2: res26: (Option[Any], scala.collection.immutable.Map[String,Any]) = (None,Map(apple -> 1, pear -> violin, banana -> object scala.Unit))