【问题标题】:How to mutate an array of integers in-place in swift through filtering如何通过过滤快速就地改变整数数组
【发布时间】:2016-10-13 04:25:28
【问题描述】:

可以在 swift 中像这样过滤数组:

var numbers = Array(1...1000000)
numbers = numbers.filter( { return $0 % 2 == 0  } ) 

是否可以过滤并避免在过滤完成时发生的复制操作,例如改变原始数组。

与此伪代码类似: numbers.MutablefilterOperation({ return $0 % 2 == 0})

在 C++ 中,与上面 Swift 中发生的事情等价的是:

std::vector<int> originalNumbers(1000000);
std::vector<int> newNumbers;
std::copy_if (originalNumbers.begin(), originalNumbers.end(), std::back_inserter(newNumbers), [](int i) { return i % 2 == 0 } );

出于性能原因我希望达到的目标:

std::vector<int> originalNumbers(1000000);
auto pos = std::remove_if(originalNumbers.begin(), originalNumbers.end(), [](int x) { return x % 2 == 0; });
originalNumbers.erase(pos, originalNumbers.end());

【问题讨论】:

  • 你必须澄清。我们是在谈论任意数组还是您生成的数组?如果它是任意的,那么任何方法都将涉及查看每个索引。如果它已生成,那么您可以使用自定义生成方法来生成“过滤”元素。
  • 你发现你当前的代码有什么不干净的地方?如果您真的对此有强烈的感觉,您可以随时编写自己的 filterInPlace 方法作为 Array 的扩展。另外顺便说一句,你可以把你的过滤器写成numbers = numbers.filter{$0 % 2 == 0}
  • Array 是一个 struct 具有值语义,它不能被变异。它的任何突变都只是替换原来的。
  • What do you find un-clean about your current code? 它的操作成本为 2 * O(n) ... 副本 O(n) 被命中一次,过滤器 O(n) 被命中一次。是的,这减少到“O(n)”,因为 Big O 表示法会丢弃标量,但老实说,2 的因子 很重要。如果 Swift 提供了一个开箱即用的filterInPlace 方法,那么就有可能实现实际的 O(n) 运行时。
  • 我也想知道同样的事情。 Apple 的 API 设计指南告诉我们以 'ed' 或 'ing' 结尾来命名非变异方法——所以我们将 sorted() 作为 sort() 的非变异对应物。那么为什么他们在命名filter() 时忽略了自己的准则呢?不应该叫filtered()吗?

标签: arrays swift filtering immutability


【解决方案1】:

此实现应该进行过滤,而不必在进程中制作整个数组的临时副本(除非它的副本被另一个变量引用,请参阅“写入时复制”)

extension Array {
    mutating func filterInPlace(isIncluded: (Element) throws -> Bool) rethrows {
        var writeIndex = self.startIndex
        for readIndex in self.indices {
            let element = self[readIndex]
            let include = try isIncluded(element)
            if include {
                if writeIndex != readIndex {
                    self[writeIndex] = element
                }
                writeIndex = self.index(after: writeIndex)
            }
        }
        self.removeLast(self.distance(from: writeIndex, to: self.endIndex))
    }
}

// example:
var arr = [6,2,6,5,2,5,6,2,2,1,6,7,3]
arr.filterInPlace { $0 % 2 == 1 }
print(arr) // [5, 5, 1, 7, 3]

【讨论】:

    猜你喜欢
    • 2018-09-17
    • 2015-10-27
    • 1970-01-01
    • 2014-09-11
    • 1970-01-01
    • 2011-12-23
    • 1970-01-01
    • 1970-01-01
    • 2021-04-11
    相关资源
    最近更新 更多