在Swift中对Big Int值进行排序

时间:2017-08-07 12:30:44

标签: ios swift sorting

我有一个问题要排序一些数字,这是首先是字符串。这个数字对于UInt64来说太大了,所以我将字符串数转换为float然后对其进行排序。这很好。但是我需要打印这些没有小数的数字。所以我试着格式化数字。但是更大的数字在格式化后会改变它的值。

这是要排序的输入数组 -
[" 6"" 31415926535897932384626433832795"" 1"" 3"" 10"" 3"" 5"]

我需要以这种格式打印输出 -

1

3

3

5

10

31415926535897932384626433832795

这是我在swift中的代码 -

import Foundation
var a = Array<Float>()
var b = ["6","31415926535897932384626433832795","1","3","10","3","5"]
a = b.map{ Float($0)! }
for i in 0..<(a.count-1){
    var min = i
    for j in (i+1)..<a.count{
        if a[j] < a[min] {
            min = j
        }
    }

    var temp = a[i]
    a[i] = a[min]
    a[min] = temp
}
for val in a{
    print(String(format: "%.0f",val.rounded(.down)))
}

我的输出是 -

1

3

3

5

6

10

31415927314585224784361549725696

如果您发现最后一个最大数字已从原始输入更改。我们欢迎所有的建议!谢谢!

3 个答案:

答案 0 :(得分:4)

您可以使用数字比较:

let values = ["6","31415926535897932384626433832795","1","3","10","3","5"]

let sortedValues = values.sorted { (value1, value2) in
    let order = value1.compare(value2, options: .numeric)
    return order == .orderedAscending
}

print(sortedValues) // ["1", "3", "3", "5", "6", "10", "31415926535897932384626433832795"]

答案 1 :(得分:2)

使用float时,大整数之间的订单可能会产生意外结果:

var str = "Hello, playground"
let inArray = [
    "6",
    "31415926535897932384626433832797",
    "31415926535897932384626433832796",
    "31415926535897932384626433832795",
    "1",
    "3"
]
let outArray = inArray.sorted {Float($0)! < Float($1)!}
print(outArray)
//->["1", "3", "6", "31415926535897932384626433832797", "31415926535897932384626433832796", "31415926535897932384626433832795"]

正如mag_zbc的答案中所述,Float只有大约7位有效数字,因此所有不太重要的数字都会丢失。

Float("31415926535897932384626433832797") == Float("31415926535897932384626433832795")
//->true

如果您的号码的数字最多为38,则可以使用Decimal(同样在mag_zbc&#39的答案中建议)。

let outWithDecimal = inArray.sorted {Decimal(string: $0)! < Decimal(string: $1)!}
print(outWithDecimal)
//->["1", "3", "6", "31415926535897932384626433832795", "31415926535897932384626433832796", "31415926535897932384626433832797"]

否则,如果您的数据包含超过38位的数字,String比较可以使用一些预处理:

(假设你的所有数字都是非负整数。)

extension String {
    func fillZeroLeft(_ length: Int) -> String {
        if self.characters.count < length {
            return String.init(repeating: "0", count: length-self.characters.count) + self
        } else {
            return self
        }
    }
}

let maxLen = inArray.lazy.map{$0.characters.count}.max()!
let outWithString = inArray.sorted {$0.fillZeroLeft(maxLen) < $1.fillZeroLeft(maxLen)}
print(outWithString)
//->["1", "3", "6", "31415926535897932384626433832795", "31415926535897932384626433832796", "31415926535897932384626433832797"]

(但Sulthan的答案中的数字比较对我来说似乎更好!)

答案 2 :(得分:0)

在Swift中使用原始类型准确表示这么大的数字是不可能的。

你的价值是〜3e + 32
UInt64的最大值为~18e + 18
Float使用24位作为有效值,这允许准确地表示高达~1.6e + 8的数字 Double使用53位作为有效值,这允许准确地表示高达~9e + 15

的数字

浮点类型(FloatDouble)能够容纳更多的值,但是它们的精确度会高于其重要数据所能保持的数字。

除了使用一些外部库之外,我建议使用NSDecimalNumber类,它应该能够容纳多达38个十进制数字 - 这对于你的例子中的数字来说已经足够了。但是,如果你需要更大的数字,那么你需要寻找一些外部库。