Swift:如何从双打数组中删除重复项?

时间:2017-04-30 21:52:41

标签: arrays swift duplicates

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

3 个答案:

答案 0 :(得分:3)

您的问题强烈建议您使用错误的数据类型。我怀疑你真的只是想修改你的模型,而不是试图在unquing点修复它,所以问题不会发生。

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

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以使它们独一无二。你可以检查是否平等。你可以打印它们,它们的行为就像十进制数字。让你的模型符合你的意思,大多数其他问题都会消失。

答案 1 :(得分:1)

您可以使用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"]

答案 2 :(得分:0)

你的问题有点复杂,因为你的双打等式是基于在小数点后的前三位数。许多线程描述了删除重复的地方,其中简单的相等适用,但我找不到包含双打的问题,并在你的问题中进行比较。

您通常使用Set来消除重复项,但Set<Double>使用不符合您要求的严格相等。

规范化值可能适用于您的情况:

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]