2016-12-04 341 views
2

我的要求是從斯卡拉陣列中刪除每個第N個元素(請注意每個第N個元素)。我寫了下面的方法來完成這項工作。因爲,我是斯卡拉新手,無法避免Java宿醉。是否有更簡單或更有效的替代方案?從斯卡拉陣列中刪除每個第N個元素

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 
} 
+0

你也可能想看看這個http://stackoverflow.com/questions/39105121/how-to-remove-every-nth-element-from-the-scala-list – Shankar

回答

1

這將使

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

你犯了一個良好的開端。考慮這種簡化。

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

謝謝。但是,您的邏輯會跳過第一條記錄(a [0] - 因爲0%n將爲0)。我的邏輯a(i-1)確保第一個元素不會丟失。 – AKK

+0

沒問題。很容易修復。 – jwvh

2

您可以分兩步功能使用zipWithIndex得到與他們的指數tupled元素的數組做到這一點,然後collect構建由只具有不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 } 
+0

我會添加'arr.toIterator。 ... .toArray'以避免創建另一個陣列 –

+0

你確定嗎?這實際上似乎讓它變慢了。 –

2

這樣的事情呢?

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

'數組(1,2,3)'與'n = 4'? '_.take(n-1)'也許? –

+0

@VictorMoroz是的,謝謝! – Dima

+0

迄今爲止沒有中間數據結構的唯一解決方案。 –

-1

我喜歡這樣的事情;

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) 

這是有效的,因爲它需要在陣列上單次通過,並從它移除每第n個元素 - 我相信這是容易看到的。 第一個案例與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) 
+0

任何人都在意解釋爲什麼這是downvoted? – Ashesh

0

如果你正在尋找性能(因爲你使用的是ArrayBuffer),你不妨用var跟蹤指數,手動增加它,並使用if進行檢查以過濾掉n多個索引的值。

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 
} 

如果我們使用while循環遍歷原始數組作爲迭代器,它會更快。

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 
} 
相關問題