从Swift数组中删除每第n个元素

9

有没有一种简单的方法可以从Swift数组中删除每个第n个元素。例如,在下面的数组中:

thisArray = [2.0, 4.0, 3.0, 1.0, 4.5, 3.3, 1.2, 3.6, 10.3, 4.4, 2.0, 13.0]

如果 n = 3 并且从第一个元素开始计数,将返回:
returnThis = [2.0, 4.0, 1.0, 4.5, 1.2, 3.6, 4.4, 2.0]
4个回答

14
// swift 4.1:
thisArray.enumerated().compactMap { index, element in index % 3 == 2 ? nil : element }
  • 使用.enumerated()方法添加索引
  • 然后使用.compactMap方法通过返回nil过滤掉索引为2、5、8等的元素,通过仅返回element剥离其余的索引。

(如果您使用Swift 4.0或更低版本,请使用.flatMap而不是.compactMap.compactMap方法是由SE-0187在Swift 4.1中引入的)

(如果您被困在Swift 2中,请使用.enumerate()代替.enumerated().)


@CameronLowellPalmer 谢谢,已更改为.compactMap() - kennytm

3
由于功能式解决方案已经发布,因此我将在这里使用一种老式的方法。
let nums = [2.0, 4.0, 3.0, 1.0, 4.5, 3.3, 1.2, 3.6, 10.3, 4.4, 2.0, 13.0]

var filteredNums = [Double]()
for elm in nums.enumerate() where elm.index % 3 != 2 {
    filteredNums.append(elm.element)
}

说实话,我觉得这比所有的函数魔法更容易阅读和构建。 - johnbakers

2

您可以通过调整索引直接从旧数组计算新数组。对于n=3,它看起来像这样:

    0 1 2 3 4 5 6 7 8 ...    旧数组索引
    | |   / /   / /
    | |  | |   / /
    | |  | |  / /
    | |  / / / / 
    0 1 2 3 4 5 6 ...        新数组索引

代码:

let thisArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let n = 3

let newCount = thisArray.count - thisArray.count/n
let newArray = (0..<newCount).map { thisArray[$0 + $0/(n - 1)] }

print(newArray) // [1, 2, 4, 5, 7, 8, 10]

从旧数组中取出n-1个元素后,需要跳过一个元素。这可以通过在映射闭包中将$0/(n-1)添加到(新的)数组索引$0来实现。


0
一种实现这个的方法是使用flatMap,它可以从数组中删除nil值,因此我们只需返回要删除的索引的nil即可:
let n = 3
let arr = [2.0, 4.0, 3.0, 1.0, 4.5, 3.3, 1.2, 3.6, 10.3, 4.4, 2.0, 13.0]
let filteredArr = arr.enumerate().flatMap {$0.index % n == n - 1 ? nil : $0.element }

对于Swift 3:

let filteredArr = thisArray.enumerated().flatMap {$0.offset % n == n - 1 ? nil : $0.element }

一般而言,你会忽略数组的第N-1个元素。

更具有功能性的解决方案可以通过步幅实现:

let filteredArr = (n-1).stride(to: arr.count, by: n).flatMap { arr[($0-n+1)..<$0] }

这里的方法是获取将被过滤掉的索引,然后连接两个连续过滤掉的索引之间的切片。

或者另一种方法是通过reduce,实际上就是filter/map/flatMap归约到reduce:

let filteredArr = arr.enumerate().reduce([]) { $1.0 % n == n - 1 ? $0 : $0 + [$1.1] }
// or, both produce the same results
let filteredArr = arr.reduce((0,[])) { ($0.0 + 1, $0.0 % n == n - 1 ? $0.1 : $0.1 + [$1]) }.1

最后,还有一种数学方法:取数组中的索引集合,减去我们不想要的索引,从排序后的结果索引构建结果数组:
let filteredArr = Set(0..<arr.count).subtract((n-1).stride(to: arr.count, by: n)).sort(<).map { arr[$0] }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接