Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在Swift中,一种有效的函数,它根据谓词将一个数组分成两个数组 注意:我目前仍在使用Swift 2.2,但也可以使用Swift 3解决方案_Arrays_Swift - Fatal编程技术网

Arrays 在Swift中,一种有效的函数,它根据谓词将一个数组分成两个数组 注意:我目前仍在使用Swift 2.2,但也可以使用Swift 3解决方案

Arrays 在Swift中,一种有效的函数,它根据谓词将一个数组分成两个数组 注意:我目前仍在使用Swift 2.2,但也可以使用Swift 3解决方案,arrays,swift,Arrays,Swift,我希望创建一个与过滤器操作非常接近的函数,除了它还保留不匹配的结果,并维护排序顺序。例如,假设您想过滤掉数组中可被3整除的数字,但仍然保留不可被3整除的数字列表 var numbers = [1,2,3,4,5,6,7,8,9,10] let partition = numbers.partition(by: { $0 % 3 == 0 }) let divisibleBy3 = Array(numbers[..<partition]) //[3,6,9] let theRest

我希望创建一个与
过滤器
操作非常接近的函数,除了它还保留不匹配的结果,并维护排序顺序。例如,假设您想过滤掉数组中可被3整除的数字,但仍然保留不可被3整除的数字列表

 var numbers = [1,2,3,4,5,6,7,8,9,10]
 let partition = numbers.partition(by: { $0 % 3 == 0 })
 let divisibleBy3 = Array(numbers[..<partition]) //[3,6,9]
 let theRest = Array(numbers[partition...]) //[1,2,4,5,7,8,10]

选项1:使用
过滤器
使用
过滤器
,您只会得到可被3整除的数字列表,而原始列表保持不变。然后可以使用相反的谓词再次过滤原始列表,但这是不必要的第二次过滤。代码如下所示:

let numbers = [1,2,3,4,5,6,7,8,9,10]
let divisibleBy3 = numbers.filter { $0 % 3 == 0 } // [3,6,9]
let theRest = numbers.filter { $0 % 3 != 0 }      // [1,2,4,5,7,8,10]
extension Collection {
    func separate(predicate: (Generator.Element) -> Bool) -> (matching: [Generator.Element], notMatching: [Generator.Element]) {
        var groups: ([Generator.Element],[Generator.Element]) = ([],[])
        for element in self {
            if predicate(element) {
                groups.0.append(element)
            } else {
                groups.1.append(element)
            }
        }
        return groups
    }
}
let numbers = [1,2,3,4,5,6,7,8,9,10]
let groups = numbers.separate { $0 % 3 == 0 }
let matching = groups.matching       // [3,6,9]
let notMatching = groups.notMatching // [1,2,4,5,7,8,10]
extension Array {
    mutating func removeIf(predicate: (Element) -> Bool) -> [Element] {
        var removedCount: Int = 0
        var removed: [Element] = []

        for (index,element) in self.enumerated() {
            if predicate(element) {
                removed.append(self.remove(at: index-removedCount))
                removedCount += 1
            }
        }

        return removed
    }
}
var numbers = [1,2,3,4,5,6,7,8,9,10]
let divisibleBy3 = numbers.removeIf { $0 % 3 == 0 }
// divisibleBy3: [3,6,9]
// numbers:      [1,2,4,5,7,8,10]
的确,这是相当可读的,但它执行两次传递的事实对我来说似乎效率低下,特别是如果谓词更复杂的话。这是实际需要的支票数量的两倍

选项2:在
集合
扩展中使用自定义
分离
功能 我的下一次尝试是扩展
集合
,并创建一个我调用的
分离的函数
。此函数将获取集合并逐个遍历元素,然后将它们添加到匹配列表或非匹配列表中。代码如下所示:

let numbers = [1,2,3,4,5,6,7,8,9,10]
let divisibleBy3 = numbers.filter { $0 % 3 == 0 } // [3,6,9]
let theRest = numbers.filter { $0 % 3 != 0 }      // [1,2,4,5,7,8,10]
extension Collection {
    func separate(predicate: (Generator.Element) -> Bool) -> (matching: [Generator.Element], notMatching: [Generator.Element]) {
        var groups: ([Generator.Element],[Generator.Element]) = ([],[])
        for element in self {
            if predicate(element) {
                groups.0.append(element)
            } else {
                groups.1.append(element)
            }
        }
        return groups
    }
}
let numbers = [1,2,3,4,5,6,7,8,9,10]
let groups = numbers.separate { $0 % 3 == 0 }
let matching = groups.matching       // [3,6,9]
let notMatching = groups.notMatching // [1,2,4,5,7,8,10]
extension Array {
    mutating func removeIf(predicate: (Element) -> Bool) -> [Element] {
        var removedCount: Int = 0
        var removed: [Element] = []

        for (index,element) in self.enumerated() {
            if predicate(element) {
                removed.append(self.remove(at: index-removedCount))
                removedCount += 1
            }
        }

        return removed
    }
}
var numbers = [1,2,3,4,5,6,7,8,9,10]
let divisibleBy3 = numbers.removeIf { $0 % 3 == 0 }
// divisibleBy3: [3,6,9]
// numbers:      [1,2,4,5,7,8,10]
然后我可以使用如下函数:

let numbers = [1,2,3,4,5,6,7,8,9,10]
let divisibleBy3 = numbers.filter { $0 % 3 == 0 } // [3,6,9]
let theRest = numbers.filter { $0 % 3 != 0 }      // [1,2,4,5,7,8,10]
extension Collection {
    func separate(predicate: (Generator.Element) -> Bool) -> (matching: [Generator.Element], notMatching: [Generator.Element]) {
        var groups: ([Generator.Element],[Generator.Element]) = ([],[])
        for element in self {
            if predicate(element) {
                groups.0.append(element)
            } else {
                groups.1.append(element)
            }
        }
        return groups
    }
}
let numbers = [1,2,3,4,5,6,7,8,9,10]
let groups = numbers.separate { $0 % 3 == 0 }
let matching = groups.matching       // [3,6,9]
let notMatching = groups.notMatching // [1,2,4,5,7,8,10]
extension Array {
    mutating func removeIf(predicate: (Element) -> Bool) -> [Element] {
        var removedCount: Int = 0
        var removed: [Element] = []

        for (index,element) in self.enumerated() {
            if predicate(element) {
                removed.append(self.remove(at: index-removedCount))
                removedCount += 1
            }
        }

        return removed
    }
}
var numbers = [1,2,3,4,5,6,7,8,9,10]
let divisibleBy3 = numbers.removeIf { $0 % 3 == 0 }
// divisibleBy3: [3,6,9]
// numbers:      [1,2,4,5,7,8,10]
这也很干净,但我唯一不喜欢的是我使用元组作为返回类型。也许其他人会不同意,但我更愿意返回与链接相同的类型
self
。但从技术上讲,您可以抓取
.matching
.notMatching
,这与
self
的类型相同,您可以将它们中的任何一个链接起来

选项3:在
数组
扩展中使用自定义、变异的
removeIf
函数 我的
separate
返回元组的问题导致我尝试创建一个函数,该函数将修改
self
,方法是删除找到的匹配项并将其添加到新列表中,最后返回匹配项列表。返回的列表是您的匹配项,数组中的这些值将被修剪。顺序在两个数组中都保持不变。代码如下所示:

let numbers = [1,2,3,4,5,6,7,8,9,10]
let divisibleBy3 = numbers.filter { $0 % 3 == 0 } // [3,6,9]
let theRest = numbers.filter { $0 % 3 != 0 }      // [1,2,4,5,7,8,10]
extension Collection {
    func separate(predicate: (Generator.Element) -> Bool) -> (matching: [Generator.Element], notMatching: [Generator.Element]) {
        var groups: ([Generator.Element],[Generator.Element]) = ([],[])
        for element in self {
            if predicate(element) {
                groups.0.append(element)
            } else {
                groups.1.append(element)
            }
        }
        return groups
    }
}
let numbers = [1,2,3,4,5,6,7,8,9,10]
let groups = numbers.separate { $0 % 3 == 0 }
let matching = groups.matching       // [3,6,9]
let notMatching = groups.notMatching // [1,2,4,5,7,8,10]
extension Array {
    mutating func removeIf(predicate: (Element) -> Bool) -> [Element] {
        var removedCount: Int = 0
        var removed: [Element] = []

        for (index,element) in self.enumerated() {
            if predicate(element) {
                removed.append(self.remove(at: index-removedCount))
                removedCount += 1
            }
        }

        return removed
    }
}
var numbers = [1,2,3,4,5,6,7,8,9,10]
let divisibleBy3 = numbers.removeIf { $0 % 3 == 0 }
// divisibleBy3: [3,6,9]
// numbers:      [1,2,4,5,7,8,10]
它是这样使用的:

let numbers = [1,2,3,4,5,6,7,8,9,10]
let divisibleBy3 = numbers.filter { $0 % 3 == 0 } // [3,6,9]
let theRest = numbers.filter { $0 % 3 != 0 }      // [1,2,4,5,7,8,10]
extension Collection {
    func separate(predicate: (Generator.Element) -> Bool) -> (matching: [Generator.Element], notMatching: [Generator.Element]) {
        var groups: ([Generator.Element],[Generator.Element]) = ([],[])
        for element in self {
            if predicate(element) {
                groups.0.append(element)
            } else {
                groups.1.append(element)
            }
        }
        return groups
    }
}
let numbers = [1,2,3,4,5,6,7,8,9,10]
let groups = numbers.separate { $0 % 3 == 0 }
let matching = groups.matching       // [3,6,9]
let notMatching = groups.notMatching // [1,2,4,5,7,8,10]
extension Array {
    mutating func removeIf(predicate: (Element) -> Bool) -> [Element] {
        var removedCount: Int = 0
        var removed: [Element] = []

        for (index,element) in self.enumerated() {
            if predicate(element) {
                removed.append(self.remove(at: index-removedCount))
                removedCount += 1
            }
        }

        return removed
    }
}
var numbers = [1,2,3,4,5,6,7,8,9,10]
let divisibleBy3 = numbers.removeIf { $0 % 3 == 0 }
// divisibleBy3: [3,6,9]
// numbers:      [1,2,4,5,7,8,10]
此函数必须在
数组
的扩展中实现,因为在特定索引处删除元素的概念不适用于常规
集合
数组
定义为
公共结构数组:RandomAccessCollection,MutableCollection
),它直接定义了
删除(位于:)
函数,而不是从继承或协议获取)

选项4:选项2和选项3的组合 我非常喜欢代码重用,在提出选项3后,我意识到我可能可以重用选项2中的
separate
函数。我提出了以下建议:

extension Array {
    mutating func removeIf(predicate: (Element) -> Bool) -> [Element] {
        let groups = self.separate(predicate: predicate)
        self = groups.notMatching
        return groups.matching
    }
}
它的使用方式与选项3相同

我关心性能,所以我通过XCTest的
度量
对每个选项进行了1000次迭代。结果如下:

Option 1: 9 ms
Option 2: 7 ms
Option 3: 10 ms
Option 4: 8 ms

选项5:基于negaipro的答案

我知道<代码>分区,但我不会考虑它,因为它没有保存排序顺序。NGAI Pro的答案本质上是代码>分区< /C> >,但它让我思考。“代码>分区的想法是交换与枢轴点匹配的元素,从而确保一端的所有东西都枢转PO。int将全部匹配谓词,而另一端不匹配。我接受了这个想法,并将操作更改为“移动到末尾”。因此,匹配项将从其位置移除并添加到末尾

extension Array {
    mutating func swapIfModified(predicate: (Element) -> Bool) -> Int {
        var matchCount = 0
        var index = 0
        while index < (count-matchCount) {
            if predicate(self[index]) {
                append(remove(at: index))
                matchCount += 1
            } else {
                index += 1
            }
        }

        return count-matchCount
    }
}
扩展数组{
变异函数swapIfModified(谓词:(元素)->Bool)->Int{
var matchCount=0
var指数=0
而索引<(计数匹配计数){
if谓词(自[索引]){
追加(删除(在:索引处))
匹配计数+=1
}否则{
指数+=1
}
}
返回计数匹配计数
}
}
在我最初使用10个数字的数组进行测试时,它与其他选项相当。但我担心行
append(remove(at:index))
的性能。因此我再次尝试了所有选项,数组从1到1000,这个选项肯定是最慢的


结论: 这些选项之间的性能差别不大。由于选项4比选项3快,并且重用了选项2中的代码,我倾向于放弃选项3。因此,当我不关心未过滤的结果时,我倾向于使用普通的旧
过滤器(同样,当我不关心过滤结果时,因为它只是使用相反的谓词),然后当我关心保留过滤和未过滤结果时,使用
separate
removeIf

问题: 那么,我是否遗漏了Swift中已经具备的功能?有没有更好的方法来实现这一点?我的扩展语法是否遗漏了任何东西(例如,任何可以使它将此概念应用到更多领域的东西)?

let objects:[Int]=Array(1..[Int],[Int])in
var值=价值
如果对象%2==0{
value.1.追加(对象)
}否则{
value.0.append(对象)
}
返回值
}
//交换和返回枢轴
扩展阵列
{
//回程枢轴
变异func swapIf(谓词:(元素)->Bool)->Int
{
var pivot=0
因为我在0..0
{
交换(&self[i]、&self[pivot])
}
枢轴+=1
}
}
回程枢轴
}
}
这是我的代码,概念是减少内存使用

我检查了“swapIf”比“removeIf”快4倍。

解决方案A 对于较少的元素