如何从Scala的列表中删除对象的首次出现? [英] How should I remove the first occurrence of an object from a list in Scala?

查看:64
本文介绍了如何从Scala的列表中删除对象的首次出现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从Scala中的列表中删除第一次出现的对象的最佳方法是什么?

What is the best way to remove the first occurrence of an object from a list in Scala?

来自Java,我习惯于使用

Coming from Java, I'm accustomed to having a List.remove(Object o) method that removes the first occurrence of an element from a list. Now that I'm working in Scala, I would expect the method to return a new immutable List instead of mutating a given list. I might also expect the remove() method to take a predicate instead of an object. Taken together, I would expect to find a method like this:

/**
 * Removes the first element of the given list that matches the given
 * predicate, if any.  To remove a specific object <code>x</code> from
 * the list, use <code>(_ == x)</code> as the predicate.
 *
 * @param toRemove
 *          a predicate indicating which element to remove
 * @return a new list with the selected object removed, or the same
 *         list if no objects satisfy the given predicate
 */
def removeFirst(toRemove: E => Boolean): List[E]

当然,我可以通过几种不同的方式自己实现此方法,但是显然没有最好的选择.我不希望将列表转换为Java列表(甚至不转换为Scala可变列表),然后再返回,尽管那肯定可以.我可以使用List.indexWhere(p: (A) ⇒ Boolean):

Of course, I can implement this method myself several different ways, but none of them jump out at me as being obviously the best. I would rather not convert my list to a Java list (or even to a Scala mutable list) and back again, although that would certainly work. I could use List.indexWhere(p: (A) ⇒ Boolean):

def removeFirst[E](list: List[E], toRemove: (E) => Boolean): List[E] = {
  val i = list.indexWhere(toRemove)
  if (i == -1)
    list
  else
    list.slice(0, i) ++ list.slice(i+1, list.size)
}

但是,将索引与链表一起使用通常不是最有效的方法.

However, using indices with linked lists is usually not the most efficient way to go.

我可以编写这样一个更有效的方法:

I can write a more efficient method like this:

def removeFirst[T](list: List[T], toRemove: (T) => Boolean): List[T] = {
  def search(toProcess: List[T], processed: List[T]): List[T] =
    toProcess match {
      case Nil => list
      case head :: tail =>
        if (toRemove(head))
          processed.reverse ++ tail
        else
          search(tail, head :: processed)
    }
  search(list, Nil)
}

仍然,这并不十分简洁.似乎很奇怪,没有一种可以让我高效而简洁地执行此操作的方法.那么,我是否缺少某些东西,还是我的最后一个解决方案真的很完善?

Still, that's not exactly succinct. It seems strange that there's not an existing method that would let me do this efficiently and succinctly. So, am I missing something, or is my last solution really as good as it gets?

推荐答案

您可以使用span稍微清理一下代码.

You can clean up the code a bit with span.

scala> def removeFirst[T](list: List[T])(pred: (T) => Boolean): List[T] = {
     |   val (before, atAndAfter) = list span (x => !pred(x))
     |   before ::: atAndAfter.drop(1)
     | }
removeFirst: [T](list: List[T])(pred: T => Boolean)List[T]

scala> removeFirst(List(1, 2, 3, 4, 3, 4)) { _ == 3 }
res1: List[Int] = List(1, 2, 4, 3, 4)

Scala Collections API概述是了解某些内容的好地方鲜为人知的方法.

The Scala Collections API overview is a great place to learn about some of the lesser known methods.

这篇关于如何从Scala的列表中删除对象的首次出现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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