iOS Swift: Eliminate trailing zeroes for CGFloat - ios

I have float value that ends in .0 or .5 (for example 10.0 or 10.5). If it ends in .0 I would like to eliminate the trailing zero. What is the easiest way to do this in Swift?
func myFunction() {
var string = pickerData[picker.selectedRowInComponent(0)]
var float = ((string as NSString).floatValue - 45) / 2
label.text = float.description
}

You should use NSNumberFormatter() to format your numbers as follow:
extension Double {
var formatted:String {
let formatter = NSNumberFormatter()
formatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
// you can set the minimum fraction digits to 0
formatter.minimumFractionDigits = 0
// and set the maximum fraction digits to 1
formatter.maximumFractionDigits = 1
return formatter.stringFromNumber(self) ?? ""
}
}
10.5.formatted // "10.5"
10.0.formatted // "10"
In your case it would look like this:
label.text = float.formatted

Related

How to make Double number to add thousand mark and set minimumFractionDigits?

I have a question about number formatter.
I want to add thousand separator mark to my double number.
And I also to set it's minimumFractionDigits, but I failed.
func formatterNumberToString(_ numberText: String, digits: Int) -> String {
let str = numberText
let formatter = Formatter.withSeparator
formatter.minimumFractionDigits = digits
let finalStr = formatter.string(for: Double(str)!)
if let finalStr = finalStr {
return finalStr
} else {
return "none"
}
}
self.formatterNumberToString("10003232.234", digits: 2) //it return 10,003,232.234
Why minimumFractionDigits not work?
Your code is working fine. The condition for minimum number of digits is met. What you probably need is to always show 2 digits. So, just add this line,
formatter.maximumFractionDigits = digits
This will display
10,003,232.23

Swift: Distance formatting

I need to convert distances in meters to kilometers.
For example I have the following array of meters:
[10, 100, 5000, 20000, 180000, 180500, 1800000]
Now I want to have these values in kilometers with minimum 3 digits overall. But only if the distance is smaller than 100 km.
[0,01 ; 0,10 ; 5,00 ; 20,0 ; 180 ; 180 ; 1800]
I have tried this with the NumberFormatter:
let numberFormatter = NumberFormatter()
numberFormatter.minimumIntegerDigits = 1
numberFormatter.minimumFractionDigits = 2
numberFormatter.maximumFractionDigits = 2
Do I need therefor a IF/ELSE or can i achieve this with the normal NumberFormatter?
Thanks in advance.
Maybe this is what you want:
let a = [10, 100, 5_000, 20_000, 180_000, 180_500, 1_800_000]
let maxIntegerDigits = Int(log(Float80(Int.max)) + 1)
let formatter = NumberFormatter()
formatter.minimumIntegerDigits = 1
let result: [String] = a.map { distance in
let inKilometers = Double(distance) / 1000
if distance < 10_000 {
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
formatter.maximumIntegerDigits = 1
}
else if distance < 100_000 {
formatter.minimumFractionDigits = 1
formatter.maximumFractionDigits = 1
formatter.maximumIntegerDigits = 2
} else {
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = 0
formatter.maximumIntegerDigits = maxIntegerDigits
}
return formatter.string(for: inKilometers) ?? ""
}
print(result) //["0.01", "0.10", "5.00", "20.0", "180", "180", "1,800"]
You can set the locale of the number formatter in order to change the grouping and decimal separators.
If you want to use NumberFormatter for this, you can create method which returns number of fraction digits which you want to have for your number
private func getNumberOfFractionDigits(for number: Double) -> Int {
switch self {
case ..<10:
return 2
case ..<100:
return 1
default:
return 0
}
}
then just set maximumFractionDigits property of formatter to result of getFractionDigits for your number divided by thousand
let dividedNumber = yourNumber / 1000
numberFormatter.numberStyle = .decimal
numberFormatter.maximumFractionDigits = getNumberOfFractionDigits(for: dividedNumber)
let formatedNumber = Double(numberFormatter.string(from: NSNumber(value: dividedNumber))!)!

Swift - How to remove a decimal from a float if the decimal is equal to 0?

I'm displaying a distance with one decimal, and I would like to remove this decimal in case it is equal to 0 (ex: 1200.0Km), how could I do that in swift?
I'm displaying this number like this:
let distanceFloat: Float = (currentUser.distance! as NSString).floatValue
distanceLabel.text = String(format: "%.1f", distanceFloat) + "Km"
Swift 3/4:
var distanceFloat1: Float = 5.0
var distanceFloat2: Float = 5.540
var distanceFloat3: Float = 5.03
extension Float {
var clean: String {
return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(self)
}
}
print("Value \(distanceFloat1.clean)") // 5
print("Value \(distanceFloat2.clean)") // 5.54
print("Value \(distanceFloat3.clean)") // 5.03
Swift 2 (Original answer)
let distanceFloat: Float = (currentUser.distance! as NSString).floatValue
distanceLabel.text = String(format: distanceFloat == floor(distanceFloat) ? “%.0f" : "%.1f", distanceFloat) + "Km"
Or as an extension:
extension Float {
var clean: String {
return self % 1 == 0 ? String(format: "%.0f", self) : String(self)
}
}
Use NSNumberFormatter:
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = 2
// Avoid not getting a zero on numbers lower than 1
// Eg: .5, .67, etc...
formatter.numberStyle = .decimal
let nums = [3.0, 5.1, 7.21, 9.311, 600.0, 0.5677, 0.6988]
for num in nums {
print(formatter.string(from: num as NSNumber) ?? "n/a")
}
Returns:
3
5.1
7.21
9.31
600
0.57
0.7
extension is the powerful way to do it.
Extension:
Code for Swift 2 (not Swift 3 or newer):
extension Float {
var cleanValue: String {
return self % 1 == 0 ? String(format: "%.0f", self) : String(self)
}
}
Usage:
var sampleValue: Float = 3.234
print(sampleValue.cleanValue)
3.234
sampleValue = 3.0
print(sampleValue.cleanValue)
3
sampleValue = 3
print(sampleValue.cleanValue)
3
Sample Playground file is here.
Update of accepted answer for swift 3:
extension Float {
var cleanValue: String {
return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(self)
}
}
usage would just be:
let someValue: Float = 3.0
print(someValue.cleanValue) //prints 3
To format it to String, follow this pattern
let aFloat: Float = 1.123
let aString: String = String(format: "%.0f", aFloat) // "1"
let aString: String = String(format: "%.1f", aFloat) // "1.1"
let aString: String = String(format: "%.2f", aFloat) // "1.12"
let aString: String = String(format: "%.3f", aFloat) // "1.123"
To cast it to Int, follow this pattern
let aInt: Int = Int(aFloat) // "1"
When you use String(format: initializer, Swift will automatically round the final digit as needed based on the following number.
You can use an extension as already mentioned, this solution is a little shorter though:
extension Float {
var shortValue: String {
return String(format: "%g", self)
}
}
Example usage:
var sample: Float = 3.234
print(sample.shortValue)
Swift 5
for Double it's same as #Frankie's answer for float
var dec: Double = 1.0
dec.clean // 1
for the extension
extension Double {
var clean: String {
return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(self)
}
}
Swift 5.5 makes it easy
Just use the new formatted() api with a default FloatingPointFormatStyle:
let values: [Double] = [1.0, 4.5, 100.0, 7]
for value in values {
print(value.formatted(FloatingPointFormatStyle()))
}
// prints "1, 4.5, 100, 7"
In Swift 4 try this.
extension CGFloat{
var cleanValue: String{
//return String(format: 1 == floor(self) ? "%.0f" : "%.2f", self)
return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(format: "%.2f", self)//
}
}
//How to use - if you enter more then two-character after (.)point, it's automatically cropping the last character and only display two characters after the point.
let strValue = "32.12"
print(\(CGFloat(strValue).cleanValue)
Formatting with maximum fraction digits, without trailing zeros
This scenario is good when a custom output precision is desired.
This solution seems roughly as fast as NumberFormatter + NSNumber solution from MirekE, but one benefit could be that we're avoiding NSObject here.
extension Double {
func string(maximumFractionDigits: Int = 2) -> String {
let s = String(format: "%.\(maximumFractionDigits)f", self)
var offset = -maximumFractionDigits - 1
for i in stride(from: 0, to: -maximumFractionDigits, by: -1) {
if s[s.index(s.endIndex, offsetBy: i - 1)] != "0" {
offset = i
break
}
}
return String(s[..<s.index(s.endIndex, offsetBy: offset)])
}
}
(works also with extension Float, but not the macOS-only type Float80)
Usage: myNumericValue.string(maximumFractionDigits: 2) or myNumericValue.string()
Output for maximumFractionDigits: 2:
1.0 → "1"
0.12 → "0.12"
0.012 → "0.01"
0.0012 → "0"
0.00012 → "0"
Simple :
Int(floor(myFloatValue))
NSNumberFormatter is your friend
let distanceFloat: Float = (currentUser.distance! as NSString).floatValue
let numberFormatter = NSNumberFormatter()
numberFormatter.positiveFormat = "###0.##"
let distance = numberFormatter.stringFromNumber(NSNumber(float: distanceFloat))!
distanceLabel.text = distance + " Km"
Here's the full code.
let numberA: Float = 123.456
let numberB: Float = 789.000
func displayNumber(number: Float) {
if number - Float(Int(number)) == 0 {
println("\(Int(number))")
} else {
println("\(number)")
}
}
displayNumber(numberA) // console output: 123.456
displayNumber(numberB) // console output: 789
Here's the most important line in-depth.
func displayNumber(number: Float) {
Strips the float's decimal digits with Int(number).
Returns the stripped number back to float to do an operation with Float(Int(number)).
Gets the decimal-digit value with number - Float(Int(number))
Checks the decimal-digit value is empty with if number - Float(Int(number)) == 0
The contents within the if and else statements doesn't need explaining.
This might be helpful too.
extension Float {
func cleanValue() -> String {
let intValue = Int(self)
if self == 0 {return "0"}
if self / Float (intValue) == 1 { return "\(intValue)" }
return "\(self)"
}
}
Usage:
let number:Float = 45.23230000
number.cleanValue()
Maybe stringByReplacingOccurrencesOfString could help you :)
let aFloat: Float = 1.000
let aString: String = String(format: "%.1f", aFloat) // "1.0"
let wantedString: String = aString.stringByReplacingOccurrencesOfString(".0", withString: "") // "1"

How can I format currency depending on decimal value?

I am using NSDecimalNumber to format currency and want the following inputs and outputs:
9.99 --> 9.99
10 --> 10
10.00 --> 10
9.90 --> 9.90
9.9 --> 9.90
0 --> 0
0.01 --> 0.01
20 --> 20
10.01 --> 10.01
How can I do this in Swift.
EDIT: Essentially if there are cents (i.e. cents > 0) then display the cents. Otherwise, don't.
Your rule is "Display two fractional digits if either is non-zero; otherwise, display no fractional digits and no decimal point”. I would do it in the most straightforward way:
let number = NSDecimalNumber(string: "12345.00")
let formatter = NSNumberFormatter()
formatter.positiveFormat = "0.00"
let formattedString = formatter.stringFromNumber(number)!
.stringByReplacingOccurrencesOfString(".00", withString: "")
You can use NSNumberFormatter's currency formatting for this. However, there doesn't seem to be a built-in way to do rounding the way you want. Here's a workaround:
let formatter = NSNumberFormatter()
formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
func numToCurrency (num: Double) -> String {
if floor(num) == num {
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = 0
}
else {
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
}
return formatter.stringFromNumber(num)!
}
numToCurrency(9) // "$9"
numToCurrency(9.9) // "$9.90"
Check the NSNumberFormatter class reference for further configuration options (you might need to set a locale for this formatter to automatically use the correct international currency sign for the current user).
(Answering here, as a closed question was re-directed to this one...)
Perhaps the most straightforward route, particularly since this is tagged "Swift", is to determine if it's a whole number or not:
if value.truncatingRemainder(dividingBy: 1) == 0 {
// it's a whole number,
// so format WITHOUT decimal places, e.g. $12
} else {
// it's a fraction,
// so format WITH decimal places, e.g. $12.25
}
the added benefit is avoiding issues with locales and currency formats... no search/replace of ".00" when you're in Germany, for example, where the format is ",00"
edit/update: Xcode 8.3 • Swift 3.1
extension Formatter {
static let noFractionDigits: NumberFormatter = {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = 0
formatter.minimumIntegerDigits = 1
return formatter
}()
static let twoFractionDigits: NumberFormatter = {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
formatter.minimumIntegerDigits = 1
return formatter
}()
}
extension FloatingPoint {
var customDescription: String {
return rounded(.down) == self ?
Formatter.noFractionDigits.string(for: self) ?? "" :
Formatter.twoFractionDigits.string(for: self) ?? ""
}
}
extension String {
var double: Double { return Double(self) ?? 0 }
}
let array = ["9.99","10","10.00","9.90","9.9"]
let results = array.map { $0.double.customDescription }
results // ["9.99", "10", "10", "9.90", "9.90"]
Here's how to create a custom formatter class to handle this for you:
import Foundation
class CustomFormatter: NSNumberFormatter {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init() {
super.init()
self.locale = NSLocale.currentLocale()
self.numberStyle = .DecimalStyle
}
func isIntegerNumber(number:NSNumber) -> Bool {
var value: NSDecimal = number.decimalValue
if NSDecimalIsNotANumber(&value) { return false }
var rounded = NSDecimal()
NSDecimalRound(&rounded, &value, 0, NSRoundingMode.RoundPlain)
return NSDecimalCompare(&rounded, &value) == NSComparisonResult.OrderedSame
}
override func stringFromNumber(number: NSNumber) -> String? {
if isIntegerNumber(number) {
self.minimumFractionDigits = 0
self.maximumFractionDigits = 0
return super.stringFromNumber(number)
}
else {
self.minimumFractionDigits = 2
self.maximumFractionDigits = 2
return super.stringFromNumber(number)
}
}
}
let formatter = CustomFormatter()
formatter.stringFromNumber(NSDecimalNumber(double: 5.00)) // -> "5"
formatter.stringFromNumber(NSDecimalNumber(double: 5.01)) // -> "5.01"
formatter.stringFromNumber(NSDecimalNumber(double: 5.10)) // -> "5.10"
Thanks to this post for the proper way to test if a NSDecimal is an integer.
I think it's best to let the currencyStyle determine the maximumFractionDigits. Just set the minimumFractionDigits to 0 where desired. The code is slightly shorter, but as a bonus if you set the locale, this way will allow for languages that don't have 2 decimal places.
Using NSNumberFormatter gives you the benefit of currency symbols, decimal places and comma’s, all in the perfect places for the different locale’s.
extension NSNumber {
func currencyString() -> String? {
let formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
if self.isEqualToNumber(self.integerValue) {
formatter.minimumFractionDigits = 0
}
return formatter.stringFromNumber(self)
}
}
let inputArray: [NSDecimalNumber] = [9.99, 10, 10.00, 9.90, 0, 0.01, 20, 10.01, 0.5, 0.055, 5.0]
let outputArray: [String] = inputArray.map({return $0.currencyString() ?? "nil"})
print(outputArray)
["$9.99", "$10", "$10", "$9.90", "$0", "$0.01", "$20", "$10.01", "$0.50", "$0.06", "$5"]
Adding a locale to a NSNumberFormatter looks like this(ex. from an SKProduct object):
formatter.locale = product!.priceLocale
For an OSX app you need to add:
formatter.formatterBehavior = .Behavior10_4

Swift - Remove Trailing Zeros From Double

What is the function that removes trailing zeros from doubles?
var double = 3.0
var double2 = 3.10
println(func(double)) // 3
println(func(double2)) // 3.1
You can do it this way but it will return a string:
var double = 3.0
var double2 = 3.10
func forTrailingZero(temp: Double) -> String {
var tempVar = String(format: "%g", temp)
return tempVar
}
forTrailingZero(double) //3
forTrailingZero(double2) //3.1
In Swift 4 you can do it like that:
extension Double {
func removeZerosFromEnd() -> String {
let formatter = NumberFormatter()
let number = NSNumber(value: self)
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = 16 //maximum digits in Double after dot (maximum precision)
return String(formatter.string(from: number) ?? "")
}
}
example of use: print (Double("128834.567891000").removeZerosFromEnd())
result: 128834.567891
You can also count how many decimal digits has your string:
import Foundation
extension Double {
func removeZerosFromEnd() -> String {
let formatter = NumberFormatter()
let number = NSNumber(value: self)
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = (self.components(separatedBy: ".").last)!.count
return String(formatter.string(from: number) ?? "")
}
}
Removing trailing zeros in output
This scenario is good when the default output precision is desired. We test the value for potential trailing zeros, and we use a different output format depending on it.
extension Double {
var stringWithoutZeroFraction: String {
return truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(self)
}
}
(works also with extension Float, but not Float80)
Output:
1.0 → "1"
0.1 → "0.1"
0.01 → "0.01"
0.001 → "0.001"
0.0001 → "0.0001"
Formatting with maximum fraction digits, without trailing zeros
This scenario is good when a custom output precision is desired.
This solution seems roughly as fast as NumberFormatter + NSNumber solution from MirekE, but one benefit could be that we're avoiding NSObject here.
extension Double {
func string(maximumFractionDigits: Int = 2) -> String {
let s = String(format: "%.\(maximumFractionDigits)f", self)
for i in stride(from: 0, to: -maximumFractionDigits, by: -1) {
if s[s.index(s.endIndex, offsetBy: i - 1)] != "0" {
return String(s[..<s.index(s.endIndex, offsetBy: i)])
}
}
return String(s[..<s.index(s.endIndex, offsetBy: -maximumFractionDigits - 1)])
}
}
(works also with extension Float, but not Float80)
Output for maximumFractionDigits: 2:
1.0 → "1"
0.12 → "0.12"
0.012 → "0.01"
0.0012 → "0"
0.00012 → "0"
Note that it performs a rounding (same as MirekE solution):
0.9950000 → "0.99"
0.9950001 → "1"
In case you're looking how to remove trailing zeros from a string:
string.replacingOccurrences(of: "^([\d,]+)$|^([\d,]+)\.0*$|^([\d,]+\.[0-9]*?)0*$", with: "$1$2$3", options: .regularExpression)
This will transform strings like "0.123000000" into "0.123"
All the answers i found was good but all of them had some problems like producing decimal numbers without the 0 in the beginning ( like .123 instead of 0.123). but these two will do the job with no problem :
extension Double {
func formatNumberWithFixedFraction(maximumFraction: Int = 8) -> String {
let stringFloatNumber = String(format: "%.\(maximumFraction)f", self)
return stringFloatNumber
}
func formatNumber(maximumFraction: Int = 8) -> String {
let formatter = NumberFormatter()
let number = NSNumber(value: self)
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = maximumFraction
formatter.numberStyle = .decimal
formatter.allowsFloats = true
let formattedNumber = formatter.string(from: number).unwrap
return formattedNumber
}
}
The first one converts 71238.12 with maxFraction of 8 to: 71238.12000000
but the second one with maxFraction of 8 converts it to: 71238.12
This one works for me, returning it as a String for a text label
func ridZero(result: Double) -> String {
let value = String(format: "%g", result)
return value
}
Following results
ridZero(result: 3.0) // "3"
ridZero(result: 3.5) // "3.5"

Resources