从Scala数组中删除每个nth元素



我的要求是从scala数组中删除每个nth元素(请注意每个nth元素)。我写了以下方法来完成这项工作。由于,我是Scala的新手,所以我无法避免Java宿醉。是否有更简单或更有效的替代方案?

def DropNthItem(a: Array[String], n: Int): Array[String] = {
 val in = a.indices.filter(_ % n != 0)
 val ab: ArrayBuffer[String] = ArrayBuffer()
 for ( i <- in)
    ab += a(i-1)
 return ab.toArray
}

您取得了一个良好的开端。考虑这个简化。

def DropNthItem(a: Array[String], n: Int): Array[String] =
  a.indices.filter(x => (x+1) % n != 0).map(a).toArray

这样的事情怎么样?

arr.grouped(n).flatMap(_.take(n-1)).toArray

您可以在两个步骤中使用zipWithIndex在两个步骤中进行此操作,以获取带有其索引的元素的数组,然后collect构建一个新的数组T 0 = i % n

def dropNth[A: reflect.ClassTag](arr: Array[A], n: Int): Array[A] =
  arr.zipWithIndex.collect { case (a, i) if (i + 1) % n != 0 => a }

这将成为

def DropNthItem(a: Array[String], n: Int): Array[String] =
   a.zipWithIndex.filter(_._2 % n != 0).map(_._1)

如果您正在寻找性能(由于您使用的是ArrayBuffer),则不妨使用var跟踪索引,手动将其递增,并使用if检查索引滤除n-multiph-riddex的值。

def dropNth[A: reflect.ClassTag](arr: Array[A], n: Int): Array[A] = {
    val buf = new scala.collection.mutable.ArrayBuffer[A]
    var i = 0
    for(a <- arr) {
        if((i + 1) % n != 0) buf += a
        i += 1
    }
    buf.toArray
}

,如果我们使用一段时间循环遍历原始数组作为迭代器。

def dropNth[A: reflect.ClassTag](arr: Array[A], n: Int): Array[A] = {
    val buf = new scala.collection.mutable.ArrayBuffer[A]
    val it = arr.iterator
    var i = 0
    while(it.hasNext) {
        val a = it.next
        if((i + 1) % n != 0) buf += a
        i += 1
    }
    buf.toArray
}

我会选择这样的东西;

def dropEvery[A](arr: Seq[A], n: Int) = arr.foldLeft((Seq.empty[A], 0)) {
  case ((acc, idx), _) if idx == n - 1 => (acc, 0)
  case ((acc, idx), el) => (acc :+ el, idx + 1)
}._1
// example: dropEvery(1 to 100, 3)
// res0: Seq[Int] = List(1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, 44, 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 100)

这是有效的,因为它需要单个通过阵列并从中删除每个元素 - 我相信这很容易看到。当idx == n - 1并忽略该索引处的元素时,第一种情况匹配,并通过acc并将计数重置为0的下一个元素。如果第一种情况不匹配,则将元素添加到acc的末尾,并将计数增加1。

由于您愿意摆脱Java 宿醉,因此您可能想使用隐式类以非常好的方式使用它:

implicit class MoreFuncs[A](arr: Seq[A]) {
  def dropEvery(n: Int) = arr.foldLeft((Seq.empty[A], 0)) {
    case ((acc, idx), _) if idx == n - 1 => (acc, 0)
    case ((acc, idx), el) => (acc :+ el, idx + 1)
  }._1
}
// example: (1 to 100 dropEvery 1) == Nil (: true)

最新更新