【问题标题】:Update the values of a list with their absolute values用绝对值更新列表的值
【发布时间】:2014-02-08 19:06:12
【问题描述】:

Scala 的新手。

我现在正试图让这段代码工作几个小时。它旨在用整数的绝对值更新 List[Int](整数列表)。 花了很长时间才弄清楚 List 是不可变的,所以发现 ListBuffer 可以成为救星,但最终将它返回​​到 List 表单中我猜会遇到一些问题。

def f (arr:List[Int]) : List[Int] =
{
  val list = new scala.collection.mutable.ListBuffer[Int]();
  val len = arr.length;
  for ( i <- 0 to len)
  {
    if(arr(i) < 0)
    {

      list.append((-1)*arr(i)) ;
    }
    else
    {
      list.append(arr(i));
    }
  }

  return list.toList;

}

这是给出这个错误:

java.lang.IndexOutOfBoundsException: 12
at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:52)
at scala.collection.immutable.List.apply(List.scala:84)
at Solution$.f(Solution.scala:7)
at Solution$delayedInit$body.apply(Solution.scala:23)
at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main$1.apply(App.scala:71)
at scala.App$$anonfun$main$1.apply(App.scala:7...

不知道这里出了什么问题。

【问题讨论】:

  • val res = list map math.absval res = for {i &lt;- list} yield math.abs(i)

标签: list function scala functional-programming listbuffer


【解决方案1】:

最好的方法是使用像 cmets 中建议的 @senia 这样的 Scala 函数。例如:

val res = list map math.abs

但是,如果您想修复您的代码,只需将 to 替换为 until。你犯了一个错误:

def f (arr:List[Int]) : List[Int] =
{
val list = new scala.collection.mutable.ListBuffer[Int]();
val len = arr.length;
for ( i <- 0 until len)
{
    if(arr(i) < 0)
    {

        list.append((-1)*arr(i)) ;
    }
    else
    {
        list.append(arr(i));
    }
}

return list.toList;

}

这里是untilto的区别:

1 to 3
// Range(1, 2, 3)

1 until 3
// Range(1, 2)

您还可以删除return; 甚至与if/else 一起使用的大括号{

【讨论】:

  • List#apply 成本为O(N),因此您的方法的复杂度为O(N^2)。至少用for ( e &lt;- arr)替换for ( i &lt;- 0 until len)
  • @senia 好点。我不是想以更好的方式编写它,只是修复它以使其正常工作,以便 user1043981 可以看到问题所在。他太接近了:)。并不是说它是最好的实现。
  • 感谢@senia 对复杂性的多个答案和洞察力。您能否为scala 中的复杂性提供一些指示。
【解决方案2】:

另一个版本使用 for 理解避免索引,

def f (arr:List[Int]) : List[Int] =
{
  val list = new scala.collection.mutable.ListBuffer[Int]();

  for {
    a <- arr
    sign = if (a < 0) -1 else 1
  } list.append(sign * a)

  return list.toList;
}

如上所述,return 可以省略。

【讨论】:

  • 为什么不def f (arr: List[Int]) = for {a &lt;- arr; sign = if (a &lt; 0) -1 else 1} yield sign * a
【解决方案3】:

您可以尝试使用 case 语句来获得更简洁的语法:

def f(arr:List[Int]):List[Int] = {
val list = scala.collection.mutable.ListBuffer[Int]()
arr.foreach{
    x =>
        x match {
        case _ if (x <0) => list+= (x*(-1))
        case _ => list +=x
    }
}
list.toList
}

【讨论】:

    【解决方案4】:

    看起来您正在尝试解决来自here 的挑战。可能您可能希望使用具有递归和不可变列表的更多功能方法。

    def f(arr: List[Int]): List[Int] = arr match {
      case Nil => Nil
      case x :: rest => java.lang.Math.abs(x) :: f(rest)
    }
    

    【讨论】:

      【解决方案5】:

      初学者友好:我就是这样写的

      def f(arr: List[Int]) : List[Int] = {
      var list = new scala.collection.mutable.ArrayBuffer[Int]();
      // var len = arr.length;
      
      for(i <-0 until arr.length) {
          list.append( math.abs(arr(i)));
      }
      
      return list.toList; }
      

      我没有做过任何时间复杂度分析,但是对于初学者来说是最容易理解的。此外,它通过了hackerrank的所有测试

      【讨论】:

      • 非常糟糕的 Scala 风格:1) 使用可变的 var 2) var 不需要,因为选择的集合已经是可变的 3) 使用不需要的 ; 4) 使用不需要的 @987654325 @
      【解决方案6】:
      def f (arr: List[Int]) : List[Int] = {
       arr.map {
           case i if 0 > i => i * -1
           case i => i
       }
      }
      

      【讨论】:

        猜你喜欢
        • 2019-01-11
        • 2021-05-25
        • 1970-01-01
        • 2021-05-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-14
        • 1970-01-01
        相关资源
        最近更新 更多