【问题标题】:Swift: How can I remove duplicates from an array of doubles?Swift:如何从双精度数组中删除重复项?
【发布时间】:2017-09-28 10:23:05
【问题描述】:

我有一个像[0.75, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0040000000000000001, ...] 这样的值数组,我需要删除重复项。我只想关注小数点后的前 3 位数字。我该怎么做?

【问题讨论】:

    标签: arrays swift duplicates


    【解决方案1】:

    您的问题强烈表明您对数据使用了错误的类型。我怀疑你真的只是想修改你的模型,这样问题就不会发生,而不是试图在唯一点上修复它。

    如果您想进行基于十进制的数学运算,您应该使用基于十进制的数字,例如NSDecimalNumber。例如,考虑到您确实有双打进入系统的情况,您可以通过这种方式以“0.001 精度”将它们转换为NSDecimalNumber

    let values = [0.75, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0040000000000000001]
    
    let behavior = NSDecimalNumberHandler(roundingMode: .plain,
                                          scale: 3,
                                          raiseOnExactness: false,
                                          raiseOnOverflow: false,
                                          raiseOnUnderflow: false,
                                          raiseOnDivideByZero: false)
    
    let decimalNumbers = values.map {
        NSDecimalNumber(value: $0).rounding(accordingToBehavior: behavior)
    }
    
    let uniqueDecimals = Set(decimalNumbers)
    

    一旦您使用了NSDecimalNumber,并应用了适当的舍入规则,那么大多数操作都会按您的预期工作。您可以将它们放入 Set 以使它们独一无二。您可以检查是否相等。您可以打印它们,它们的行为就像十进制数。让你的模型符合你的意思,其他大多数问题都会消失。

    【讨论】:

    • 谢谢。我完全迷失了寻找那个初始化。
    • 完全不相关,但我刚刚看了你的 Do iOS 2016 谈话。我喜欢它,它将成为我解释 sum-types 与 product-types 的首选,以及为什么人们不应该使用并行数组来存储应该在结构中绑定在一起的数据成员。做得好! :)
    【解决方案2】:

    您可以使用 NumberFormatter 固定最小和最大小数位数,并使用集合过滤重复元素:

    let array = [0.75, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0040000000000000001]
    
    let numberFormatter = NumberFormatter()
    numberFormatter.numberStyle = .decimal
    numberFormatter.minimumFractionDigits = 3
    numberFormatter.maximumFractionDigits = 3
    

    var set = Set<String>()
    let orderedSet: [Double] = array.flatMap {
        guard let string = numberFormatter.string(for: $0) else { return nil }
        return set.insert(string).inserted ? $0 : nil
    }
    
    orderedSet   // [0.75, 0.005, 0.004]
    

    如果您需要字符串(如 @Hamish 建议的那样):

    var set = Set<String>()
    let orderedSet: [String] = array.flatMap {
        guard let string = numberFormatter.string(for: $0) else { return nil }
        return set.insert(string).inserted ? string : nil
    }
    
    orderedSet   // ["0.750", "0.005", "0.004"]
    

    【讨论】:

    • 返回[0.75, 0.0050000000000000001, 0.0040000000000000001]
    • 如果你愿意,我可以返回字符串
    • 是的,那行得通。然后我可以稍后将它们转换为双打。
    • 在您的第一个示例中,您也可以说 return set.insert(string).inserted ? $0 : nil 而不是 if-else,只需将 $0 替换为 string 即可获得字符串数组(无需单独的 @ 987654328@).
    • @Hamish 好多了。我也更喜欢三元运算符。
    【解决方案3】:

    您的问题有点复杂,因为您的 Doubles 相等性基于 小数点后的前 3 位。许多线程都描述了在应用简单相等的情况下删除重复项,但我在您的问题中找不到一个包括带有比较的 Doubles。

    您通常使用Set 来消除重复,但Set&lt;Double&gt; 使用严格相等,这不能满足您的要求。

    标准化值可能适用于您的情况:

    extension Double {
        var my_normalized: Double {
            return (self * 1000).rounded() / 1000
        }
    }
    
    print(0.0050000000000000001.my_normalized == 0.0051.my_normalized) //->true
    

    使用它,您可以编写如下内容:

    let arr = [0.75, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0050000000000000001, 0.0040000000000000001 /*,...*/]
    
    var valueSet: Set<Double> = []
    var result: [Double] = []
    arr.forEach {value in
        let normalizedValue = value.my_normalized
        if !valueSet.contains(normalizedValue) {
            valueSet.update(with: normalizedValue)
            result.append(value)
        }
    }
    print(result) //->[0.75, 0.0050000000000000001, 0.0040000000000000001]
    

    如果你不介意结果的顺序,它可以包含规范化的值,代码可以更简单:

    let simpleResult = Array(Set(arr.map {$0.my_normalized}))
    print(simpleResult) //->[0.75, 0.0050000000000000001, 0.0040000000000000001]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-21
      • 2013-02-23
      • 1970-01-01
      • 1970-01-01
      • 2017-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多