有没有一种简单的方法可以从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]
// 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()
.)
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)
}
您可以通过调整索引直接从旧数组计算新数组。对于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
来实现。
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] }
.compactMap()
。 - kennytm