NSNumberFormatter : Show 'k' instead of ',000' in large numbers? - swift

I'd like to change my large numbers from 100,000 to $100K if this is possible.
This is what I have so far:
let valueFormatter = NSNumberFormatter()
valueFormatter.locale = NSLocale.currentLocale()
valueFormatter.numberStyle = .CurrencyStyle
valueFormatter.maximumFractionDigits = 0
My Question
Using NSNumberFormatter, how can I output $100K rather than $100,000?
My original question:
This is what I have so far:
self.lineChartView.leftAxis.valueFormatter = NSNumberFormatter()
self.lineChartView.leftAxis.valueFormatter?.locale = NSLocale.currentLocale()
self.lineChartView.leftAxis.valueFormatter?.numberStyle = .CurrencyStyle
self.lineChartView.leftAxis.valueFormatter?.maximumFractionDigits = 0
Which Translates to:
let valueFormatter = NSNumberFormatter()
valueFormatter.locale = NSLocale.currentLocale()
valueFormatter.numberStyle = .CurrencyStyle
valueFormatter.maximumFractionDigits = 0
My output looks like this:
My Question
Using NSNumberFormatter, how can I output $100K rather than $100,000?
update:
I wanted to provide context as to whats going on, watch comments.
func setDollarsData(months: [String], range: Double) {
var dataSets: [LineChartDataSet] = [LineChartDataSet]()
var yVals: [ChartDataEntry] = [ChartDataEntry]()
for var i = 0; i < months.count; i++ {
// I'm adding my values here in value:, value takes a Double
yVals.append(ChartDataEntry(value: county[userFavs[0]]![i], xIndex: i))
}
let set1: LineChartDataSet = LineChartDataSet(yVals: yVals, label: self.userFavs[0])
set1.axisDependency = .Left
set1.setColor(UIColor.redColor().colorWithAlphaComponent(0.5))
set1.setCircleColor(UIColor.redColor())
set1.lineWidth = 2.0
set1.circleRadius = 6.0
set1.fillAlpha = 65 / 255.0
dataSets.append(set1)
let data: LineChartData = LineChartData(xVals: months, dataSets: dataSets)
data.setValueTextColor(UIColor.whiteColor())
// this is where I set the number formatter
self.lineChartView.gridBackgroundColor = UIColor.darkGrayColor()
self.lineChartView.leftAxis.startAtZeroEnabled = false
self.lineChartView.leftAxis.valueFormatter = NSNumberFormatter()
self.lineChartView.leftAxis.valueFormatter?.locale = NSLocale.currentLocale()
self.lineChartView.leftAxis.valueFormatter?.numberStyle = .CurrencyStyle
self.lineChartView.leftAxis.valueFormatter?.maximumFractionDigits = 0
// set it to the chart // END OF THE LINE
self.lineChartView.data = data // outputs to my chart
}
As you can see, once I dump the numbers into yVals, I lose access to them so those extensions will only work if I hack into the framework.

edit/update
Swift 3 or later
extension FloatingPoint {
var kFormatted: String {
return String(format: self >= 1000 ? "$%.0fK" : "$%.0f", (self >= 1000 ? self/1000 : self) as! CVarArg )
}
}
The you can use it like this to format your output:
10.0.kFormatted // "$10"
100.0.kFormatted // "$100"
1000.0.kFormatted // "$1K"
10000.0.kFormatted // "$10K"
162000.0.kFormatted // "$162K"
153000.0.kFormatted // "$153K"
144000.0.kFormatted // "$144K"
135000.0.kFormatted // "$135K"
126000.0.kFormatted // "$126K"

I've bumped into the same issue and solved it by implementing a custom formatter. Just started coding in Swift, so the code might not be the most idiomatic.
open class KNumberFormatter : NumberFormatter {
override open func string(for obj: Any?) -> String? {
if let num = obj as? NSNumber {
let suffixes = ["", "k", "M", "B"]
var idx = 0
var d = num.doubleValue
while idx < 4 && abs(d) >= 1000.0 {
d /= 1000.0
idx += 1
}
var currencyCode = ""
if self.currencySymbol != nil {
currencyCode = self.currencySymbol!
}
let numStr = String(format: "%.1f", d)
return currencyCode + numStr + suffixes[idx]
}
return nil
}
}

I think you can add an extension to NSNumberFormatter. Try the following, I didn't test it so let me know in the comment if it needs to be edited
extension NSNumberFormatter {
func dividedByK(number: Int)->String{
if (number % 1000) == 0 {
let numberK = Int(number / 1000)
return "\(numberK)K"
}
return "\(number)"
}
}

Related

Minimum Window Substring in Swift exceeds LeetCode runtime benchmark

This is a popular question on LeetCode:
Given two strings s and t of lengths m and n respectively,
return the minimum window substring of s such that every character in t (including duplicates)
is included in the window. If there is no such substring, return the empty string "".
The testcases will be generated such that the answer is unique.
A substring is a contiguous sequence of characters within the string.
Example:
Input: s = "ADOBECODEBANC", t = "ABC"
Output: "BANC"
Explanation: The minimum window substring "BANC" includes 'A', 'B', and 'C' from string t.
I converted the java solution provided by LeetCode to Swift since this is the language I am practicing in. Here is my code below:
func minWindowSlidingWindow(_ s: String, _ t: String) -> String
{
if s == t
{
return s
}
var uniqueCharacterHashTable: [Character: Int] = [:]
for character in t
{
if let countOfChar = uniqueCharacterHashTable[character]
{
uniqueCharacterHashTable[character] = countOfChar + 1
continue
}
uniqueCharacterHashTable[character] = 1
}
let uniqueCharactersRequired = uniqueCharacterHashTable.keys.count
var uniqueCharactersFormed = 0
var currentWindowCharacterHashTable: [Character: Int] = [:]
var minSequenceSize = Int.max
var minimumSequenceStart = 0
var minimumSequenceEnd = 0
var currentStartIndexInt = 0
var currentEndIndexInt = 0
while currentEndIndexInt < s.count
{
let endIndex = s.index(s.startIndex, offsetBy: currentEndIndexInt)
var currentCharacter = s[endIndex]
if var characterCount = currentWindowCharacterHashTable[currentCharacter]
{
characterCount += 1
currentWindowCharacterHashTable[currentCharacter] = characterCount
}
else
{
currentWindowCharacterHashTable[currentCharacter] = 1
}
if let _ = uniqueCharacterHashTable[currentCharacter],
currentWindowCharacterHashTable[currentCharacter] == uniqueCharacterHashTable[currentCharacter]
{
uniqueCharactersFormed += 1
}
while currentStartIndexInt <= currentEndIndexInt && uniqueCharactersFormed == uniqueCharactersRequired
{
let startIndex = s.index(s.startIndex, offsetBy: currentStartIndexInt)
currentCharacter = s[startIndex]
if minSequenceSize == Int.max || currentEndIndexInt - currentStartIndexInt + 1 < minSequenceSize
{
minSequenceSize = currentEndIndexInt - currentStartIndexInt + 1
minimumSequenceStart = currentStartIndexInt
minimumSequenceEnd = currentEndIndexInt
}
if let characterCountInWindow = currentWindowCharacterHashTable[currentCharacter]
{
currentWindowCharacterHashTable[currentCharacter] = characterCountInWindow - 1
}
if let _ = uniqueCharacterHashTable[currentCharacter],
let currentCharOriginalCount = uniqueCharacterHashTable[currentCharacter],
let charInWindowCount = currentWindowCharacterHashTable[currentCharacter],
currentCharOriginalCount > charInWindowCount
{
uniqueCharactersFormed -= 1
}
currentStartIndexInt += 1
}
currentEndIndexInt += 1
}
if minSequenceSize == Int.max
{
return ""
}
let startIndex = s.index(s.startIndex, offsetBy: minimumSequenceStart)
let endIndex = s.index(s.startIndex, offsetBy: minimumSequenceEnd)
return String(s[startIndex ... endIndex])
}
This works for the basic test cases but as the string size gets huge like 100,000 for example - it gets super slow even though I use the same data structures (I think) as suggested in the Java solution.
Can anyone point me as to where the bottleneck in this code lies and how could I optimize this further.

Swift MeasurementFormatter get string without symbol

I need to calculate pace of runner and I use that code
static func pace(distance: Measurement<UnitLength>, seconds: Int, outputUnit: UnitSpeed) -> String {
let formatter = MeasurementFormatter()
formatter.unitOptions = [.providedUnit]
let speedMagnitude = seconds != 0 ? distance.value / Double(seconds) : 0
let speed = Measurement(value: speedMagnitude, unit: UnitSpeed.metersPerSecond)
let avgPace = formatter.string(from: speed.converted(to: outputUnit))
return avgPace.replacingOccurrences(of: " min/km", with: "")
}
And I have extension for UnitSpeed
extension UnitSpeed {
class var minutesPerKilometer: UnitSpeed {
return UnitSpeed(symbol: "min/km", converter: UnitConverterPace(coefficient: 60.0 / 1000.0))
}
class var minutesPerMile: UnitSpeed {
return UnitSpeed(symbol: "min/mi", converter: UnitConverterPace(coefficient: 60.0 / 1609.34))
}
}
I don't like these lines:
let avgPace = formatter.string(from: speed.converted(to: outputUnit))
return avgPace.replacingOccurrences(of: " min/km", with: "")
Question is how to get clean value from formatter without replacingOccurrences?

Get a Decimal from a String

I have a problem to get a Decimal here.
I have tried this code but the results is 9.0 , How can i get 0.9 ?
let distances = "0.9 mil"
let stratr = distances.characters.split{$0 == " "}.map(String.init)
for item in stratr {
let components = item.components(separatedBy: NSCharacterSet.decimalDigits.inverted)
let part = components.joined(separator: "")
if let doubVal = Double(part) {
print("this is a number -> \(doubVal)")
}
You can separate the string by the space character and then initialize a Float using the first component.
let str = "0.9 mil"
let decimal = str.components(separatedBy: " ").first.flatMap { Float($0) }
print(decimal) // 0.9
The String struct provides an instance method that can be used to remove characters based on a given CharacterSet. In this case, you can use the letters and whitespaces character sets to isolate your decimal value and then create a Decimal from it.
let distances = "0.9 mil"
let decimal = Decimal(string: distances.trimmingCharacters(in: CharacterSet.letters.union(.whitespaces)))
if let decimal = decimal {
print(decimal) // Prints 0.9
}
extension String {
/// "0.9 mil" => "0.9"
var decimals: String {
return trimmingCharacters(in: CharacterSet.decimalDigits.inverted)
}
/// "0.9" => 0.9
var doubleValue: Double {
return Double(self) ?? 0
}
}
Usage:
let distance = "0.9 mil"
print(distance.decimals) // "0.9"
print(distance.decimals.doubleValue) // 0.9
print(distance.doubleValue) // 0 (because Double("0.9 mil") => nil)
Never mind i find the Answer
let distances = "0.9 mil"
let stratr = distances.characters.split{$0 == " "}.map(String.init)
for item in stratr {
let components = item.components(separatedBy: NSCharacterSet.decimalDigits.inverted)
let part = components.joined(separator: ".")
if let doubVal = Double(part) {
print("this is a number -> \(doubVal)")
}
I think when i set Joined(separator : ".") it will joined the String with an "." as separator

How do I create an x-axis with Swift Charts with 1 unit per day instead of 1 unit per data point?

I have a chart that takes time series data. The time series data is recorded at most once per day, but on an irregular schedule. I.e., the data could look like this:
1/1, 1500
1/13, 1600
1/14, 1700
2/22, 1800
5/1, 1400
Using Charts, my line graph populates the x-axis with one unit per data point (i.e., in the example above, there would be 5 units on the xaxis, instead of ~120 days)
How do I create the x-axis with units for all dates in range?
The code for my chart:
func setChartData(data: ([String], [Double])) {
var yVals1 = [ChartDataEntry]()
for i in 0 ..< data.0.count {
yVals1.append(ChartDataEntry(value: data.1[i], xIndex: i))
}
let set1: LineChartDataSet = LineChartDataSet(yVals: yVals1, label: nil)
set1.axisDependency = .Left
set1.setColor(UIColor(red:0.502, green:0.580, blue:0.784, alpha:1.000))
set1.lineWidth = 2.0
set1.fillAlpha = 1
set1.fillColor = UIColor(red:0.502, green:0.580, blue:0.784, alpha:1.000)
set1.highlightColor = UIColor.whiteColor()
set1.drawValuesEnabled = false
set1.drawCirclesEnabled = false
set1.drawFilledEnabled = true
var dataSets : [LineChartDataSet] = [LineChartDataSet]()
dataSets.append(set1)
let data: LineChartData = LineChartData(xVals: data.0, dataSets: dataSets)
data.setValueTextColor(UIColor.whiteColor())
let legend = lineChartView.legend
legend.enabled = false
let xAxis = lineChartView.xAxis
xAxis.drawGridLinesEnabled = false
xAxis.drawAxisLineEnabled = false
xAxis.labelPosition = .Bottom
let rightAxis = lineChartView.rightAxis
rightAxis.drawAxisLineEnabled = false
rightAxis.drawLabelsEnabled = false
rightAxis.drawGridLinesEnabled = false
let leftAxis = lineChartView.leftAxis
leftAxis.drawAxisLineEnabled = false
leftAxis.gridColor = UIColor.blackColor().colorWithAlphaComponent(0.1)
leftAxis.gridLineWidth = 2
self.lineChartView.data = data
}
Instead of passing in the datapoints directly, transform the datapoints to include all relevant days as x-values (1 day intervals, even if there is no associated y-value for that day) and appropriately fill in the y-values where they exist.
Build an array of x-values that contains 1 element per day
If that day has a value, then add the value to the y-value array. Otherwise add nil to the y-value array.
Code:
struct StatsViewModel {
var exercise: Exercise
var workoutDates: ([String], [Double?]) {
if let lastWorkout = exercise.workoutDiary.last, firstWorkout = exercise.workoutDiary.first {
var dates = [String]()
var stats = [Double?]()
let ti:NSTimeInterval = 24*60*60 //one day
let dateFrom = firstWorkout.date
let dateTo = lastWorkout.date
var nextDate = dateFrom
let endDate = dateTo.dateByAddingTimeInterval(ti)
while nextDate.compare(endDate) == NSComparisonResult.OrderedAscending
{
dates.append(nextDate.myPrettyString)
let workout = exercise.workoutDiary.filter { $0.date.myPrettyString == nextDate.myPrettyString }.first
if let workout = workout {
stats.append(Double(workout.totalVolume))
} else {
stats.append(nil)
}
nextDate = nextDate.dateByAddingTimeInterval(ti)
}
return (dates, stats)
}
return ([], [])
}
}
Create the ChartDataEntry from the data points generated above, accounting for nil:
var statsViewModel: StatsViewModel!
override func viewDidLoad() {
setChartData(statsViewModel.workoutDates)
}
func setChartData(data: ([String], [Double?])) {
var yVals1 = [ChartDataEntry]()
for i in 0 ..< data.0.count {
if let yval = data.1[i] {
yVals1.append(ChartDataEntry(value: yval, xIndex: i))
}
}
let set1: LineChartDataSet = LineChartDataSet(yVals: yVals1, label: nil)
var dataSets : [LineChartDataSet] = [LineChartDataSet]()
dataSets.append(set1)
let data: LineChartData = LineChartData(xVals: data.0, dataSets: dataSets)
data.setValueTextColor(UIColor.whiteColor())
...
}
The accepted answer is obsolete due to Chart API changes.
ChartDataEntry values must consist of (x, y): (Double, Double) and cannot
contain String, though you use a custom display formatter to show the data instead.
Setup a MonthTimeXAxisValueFormatter which implements the protocol IAxisValueFormatter to return String values:
class MonthTimeXAxisValueFormatter: IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MMM"
let timeStamp = Date(timeIntervalSince1970: value)
return dateFormatter.string(from: timeStamp)
}
}
// Setup the x-axis with this formatter.
lineChart.xAxis.valueFormatter = MonthTimeXAxisValueFormatter()
The x-values here should be generated as:
func chartDataPoints(from xYValues: [Date: Double]) -> [ChartDataEntry] {
assert(!xYValues.isEmpty)
var dataPoints: [ChartDataEntry] = []
var startDate = xYValues.keys.sorted(by: <).first!
let endDate = xYValues.keys.sorted(by: >).first!
repeat {
guard let yValue = xYValues[startDate] else {
startDate = startDate.advanced(by: TimeInterval(24 * 60 * 60))
continue
}
dataPoints.append(ChartDataEntry(x: Double(startDate.timeIntervalSince1970), y: yValue))
startDate = startDate.advanced(by: TimeInterval(24 * 60 * 60))
} while startDate <= endDate
return dataPoints
}

Precision String Format Specifier In Swift

Below is how I would have previously truncated a float to two decimal places
NSLog(#" %.02f %.02f %.02f", r, g, b);
I checked the docs and the eBook but haven't been able to figure it out. Thanks!
The following code:
import Foundation // required for String(format: _, _)
print(String(format: "a float number: %.2f", 1.0321))
will output:
a float number: 1.03
My best solution so far, following from David's response:
import Foundation
extension Int {
func format(f: String) -> String {
return String(format: "%\(f)d", self)
}
}
extension Double {
func format(f: String) -> String {
return String(format: "%\(f)f", self)
}
}
let someInt = 4, someIntFormat = "03"
println("The integer number \(someInt) formatted with \"\(someIntFormat)\" looks like \(someInt.format(someIntFormat))")
// The integer number 4 formatted with "03" looks like 004
let someDouble = 3.14159265359, someDoubleFormat = ".3"
println("The floating point number \(someDouble) formatted with \"\(someDoubleFormat)\" looks like \(someDouble.format(someDoubleFormat))")
// The floating point number 3.14159265359 formatted with ".3" looks like 3.142
I think this is the most Swift-like solution, tying the formatting operations directly to the data type. It may well be that there is a built-in library of formatting operations somewhere, or maybe it will be released soon. Keep in mind that the language is still in beta.
I found String.localizedStringWithFormat to work quite well:
Example:
let value: Float = 0.33333
let unit: String = "mph"
yourUILabel.text = String.localizedStringWithFormat("%.2f %#", value, unit)
This is a very fast and simple way who doesn't need complex solution.
let duration = String(format: "%.01f", 3.32323242)
// result = 3.3
Most answers here are valid. However, in case you will format the number often, consider extending the Float class to add a method that returns a formatted string. See example code below. This one achieves the same goal by using a number formatter and extension.
extension Float {
func string(fractionDigits:Int) -> String {
let formatter = NSNumberFormatter()
formatter.minimumFractionDigits = fractionDigits
formatter.maximumFractionDigits = fractionDigits
return formatter.stringFromNumber(self) ?? "\(self)"
}
}
let myVelocity:Float = 12.32982342034
println("The velocity is \(myVelocity.string(2))")
println("The velocity is \(myVelocity.string(1))")
The console shows:
The velocity is 12.33
The velocity is 12.3
SWIFT 3.1 update
extension Float {
func string(fractionDigits:Int) -> String {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = fractionDigits
formatter.maximumFractionDigits = fractionDigits
return formatter.string(from: NSNumber(value: self)) ?? "\(self)"
}
}
You can't do it (yet) with string interpolation. Your best bet is still going to be NSString formatting:
println(NSString(format:"%.2f", sqrt(2.0)))
Extrapolating from python, it seems like a reasonable syntax might be:
#infix func % (value:Double, format:String) -> String {
return NSString(format:format, value)
}
Which then allows you to use them as:
M_PI % "%5.3f" // "3.142"
You can define similar operators for all of the numeric types, unfortunately I haven't found a way to do it with generics.
Swift 5 Update
As of at least Swift 5, String directly supports the format: initializer, so there's no need to use NSString and the #infix attribute is no longer needed which means the samples above should be written as:
println(String(format:"%.2f", sqrt(2.0)))
func %(value:Double, format:String) -> String {
return String(format:format, value)
}
Double.pi % "%5.3f" // "3.142"
Why make it so complicated? You can use this instead:
import UIKit
let PI = 3.14159265359
round( PI ) // 3.0 rounded to the nearest decimal
round( PI * 100 ) / 100 //3.14 rounded to the nearest hundredth
round( PI * 1000 ) / 1000 // 3.142 rounded to the nearest thousandth
See it work in Playground.
PS: Solution from: http://rrike.sh/xcode/rounding-various-decimal-places-swift/
import Foundation
extension CGFloat {
var string1: String {
return String(format: "%.1f", self)
}
var string2: String {
return String(format: "%.2f", self)
}
}
Usage
let offset = CGPoint(1.23, 4.56)
print("offset: \(offset.x.string1) x \(offset.y.string1)")
// offset: 1.2 x 4.6
A more elegant and generic solution is to rewrite ruby / python % operator:
// Updated for beta 5
func %(format:String, args:[CVarArgType]) -> String {
return NSString(format:format, arguments:getVaList(args))
}
"Hello %#, This is pi : %.2f" % ["World", M_PI]
Details
Xcode 9.3, Swift 4.1
Xcode 10.2.1 (10E1001), Swift 5
Solution 1
func rounded() -> Double
(5.2).rounded()
// 5.0
(5.5).rounded()
// 6.0
(-5.2).rounded()
// -5.0
(-5.5).rounded()
// -6.0
func rounded(_ rule: FloatingPointRoundingRule) -> Double
let x = 6.5
// Equivalent to the C 'round' function:
print(x.rounded(.toNearestOrAwayFromZero))
// Prints "7.0"
// Equivalent to the C 'trunc' function:
print(x.rounded(.towardZero))
// Prints "6.0"
// Equivalent to the C 'ceil' function:
print(x.rounded(.up))
// Prints "7.0"
// Equivalent to the C 'floor' function:
print(x.rounded(.down))
// Prints "6.0"
mutating func round()
var x = 5.2
x.round()
// x == 5.0
var y = 5.5
y.round()
// y == 6.0
var z = -5.5
z.round()
// z == -6.0
mutating func round(_ rule: FloatingPointRoundingRule)
// Equivalent to the C 'round' function:
var w = 6.5
w.round(.toNearestOrAwayFromZero)
// w == 7.0
// Equivalent to the C 'trunc' function:
var x = 6.5
x.round(.towardZero)
// x == 6.0
// Equivalent to the C 'ceil' function:
var y = 6.5
y.round(.up)
// y == 7.0
// Equivalent to the C 'floor' function:
var z = 6.5
z.round(.down)
// z == 6.0
Solution 2
extension Numeric {
private func _precision(number: NSNumber, formatter: NumberFormatter) -> Self? {
if let formatedNumString = formatter.string(from: number),
let formatedNum = formatter.number(from: formatedNumString) {
return formatedNum as? Self
}
return nil
}
private func toNSNumber() -> NSNumber? {
if let num = self as? NSNumber { return num }
guard let string = self as? String, let double = Double(string) else { return nil }
return NSNumber(value: double)
}
func precision(_ minimumFractionDigits: Int,
roundingMode: NumberFormatter.RoundingMode = NumberFormatter.RoundingMode.halfUp) -> Self? {
guard let number = toNSNumber() else { return nil }
let formatter = NumberFormatter()
formatter.minimumFractionDigits = minimumFractionDigits
formatter.roundingMode = roundingMode
return _precision(number: number, formatter: formatter)
}
func precision(with numberFormatter: NumberFormatter) -> String? {
guard let number = toNSNumber() else { return nil }
return numberFormatter.string(from: number)
}
}
Usage
_ = 123.44.precision(2)
_ = 123.44.precision(3, roundingMode: .up)
let numberFormatter = NumberFormatter()
numberFormatter.minimumFractionDigits = 1
numberFormatter.groupingSeparator = " "
let num = 222.3333
_ = num.precision(2)
Full sample
func option1<T: Numeric>(value: T, numerFormatter: NumberFormatter? = nil) {
print("Type: \(type(of: value))")
print("Original Value: \(value)")
let value1 = value.precision(2)
print("value1 = \(value1 != nil ? "\(value1!)" : "nil")")
let value2 = value.precision(5)
print("value2 = \(value2 != nil ? "\(value2!)" : "nil")")
if let value1 = value1, let value2 = value2 {
print("value1 + value2 = \(value1 + value2)")
}
print("")
}
func option2<T: Numeric>(value: T, numberFormatter: NumberFormatter) {
print("Type: \(type(of: value))")
print("Original Value: \(value)")
let value1 = value.precision(with: numberFormatter)
print("formated value = \(value1 != nil ? "\(value1!)" : "nil")\n")
}
func test(with double: Double) {
print("===========================\nTest with: \(double)\n")
let float = Float(double)
let float32 = Float32(double)
let float64 = Float64(double)
let float80 = Float80(double)
let cgfloat = CGFloat(double)
// Exapmle 1
print("-- Option1\n")
option1(value: double)
option1(value: float)
option1(value: float32)
option1(value: float64)
option1(value: float80)
option1(value: cgfloat)
// Exapmle 2
let numberFormatter = NumberFormatter()
numberFormatter.formatterBehavior = .behavior10_4
numberFormatter.minimumIntegerDigits = 1
numberFormatter.minimumFractionDigits = 4
numberFormatter.maximumFractionDigits = 9
numberFormatter.usesGroupingSeparator = true
numberFormatter.groupingSeparator = " "
numberFormatter.groupingSize = 3
print("-- Option 2\n")
option2(value: double, numberFormatter: numberFormatter)
option2(value: float, numberFormatter: numberFormatter)
option2(value: float32, numberFormatter: numberFormatter)
option2(value: float64, numberFormatter: numberFormatter)
option2(value: float80, numberFormatter: numberFormatter)
option2(value: cgfloat, numberFormatter: numberFormatter)
}
test(with: 123.22)
test(with: 1234567890987654321.0987654321)
Output
===========================
Test with: 123.22
-- Option1
Type: Double
Original Value: 123.22
value1 = 123.22
value2 = 123.22
value1 + value2 = 246.44
Type: Float
Original Value: 123.22
value1 = nil
value2 = nil
Type: Float
Original Value: 123.22
value1 = nil
value2 = nil
Type: Double
Original Value: 123.22
value1 = 123.22
value2 = 123.22
value1 + value2 = 246.44
Type: Float80
Original Value: 123.21999999999999886
value1 = nil
value2 = nil
Type: CGFloat
Original Value: 123.22
value1 = 123.22
value2 = 123.22
value1 + value2 = 246.44
-- Option 2
Type: Double
Original Value: 123.22
formatted value = 123.2200
Type: Float
Original Value: 123.22
formatted value = 123.220001221
Type: Float
Original Value: 123.22
formatted value = 123.220001221
Type: Double
Original Value: 123.22
formatted value = 123.2200
Type: Float80
Original Value: 123.21999999999999886
formatted value = nil
Type: CGFloat
Original Value: 123.22
formatted value = 123.2200
===========================
Test with: 1.2345678909876544e+18
-- Option1
Type: Double
Original Value: 1.2345678909876544e+18
value1 = 1.23456789098765e+18
value2 = 1.23456789098765e+18
value1 + value2 = 2.4691357819753e+18
Type: Float
Original Value: 1.234568e+18
value1 = nil
value2 = nil
Type: Float
Original Value: 1.234568e+18
value1 = nil
value2 = nil
Type: Double
Original Value: 1.2345678909876544e+18
value1 = 1.23456789098765e+18
value2 = 1.23456789098765e+18
value1 + value2 = 2.4691357819753e+18
Type: Float80
Original Value: 1234567890987654400.0
value1 = nil
value2 = nil
Type: CGFloat
Original Value: 1.2345678909876544e+18
value1 = 1.23456789098765e+18
value2 = 1.23456789098765e+18
value1 + value2 = 2.4691357819753e+18
-- Option 2
Type: Double
Original Value: 1.2345678909876544e+18
formatted value = 1 234 567 890 987 650 000.0000
Type: Float
Original Value: 1.234568e+18
formatted value = 1 234 567 939 550 610 000.0000
Type: Float
Original Value: 1.234568e+18
formatted value = 1 234 567 939 550 610 000.0000
Type: Double
Original Value: 1.2345678909876544e+18
formatted value = 1 234 567 890 987 650 000.0000
Type: Float80
Original Value: 1234567890987654400.0
formatted value = nil
Type: CGFloat
Original Value: 1.2345678909876544e+18
formatted value = 1 234 567 890 987 650 000.0000
After iOS 15+ this solution is recommended:
2.31234.formatted(.number.precision(.fractionLength(1)))
Swift 4
let string = String(format: "%.2f", locale: Locale.current, arguments: 15.123)
You can still use NSLog in Swift as in Objective-C just without the # sign.
NSLog("%.02f %.02f %.02f", r, g, b)
Edit: After working with Swift since a while I would like to add also this variation
var r=1.2
var g=1.3
var b=1.4
NSLog("\(r) \(g) \(b)")
Output:
2014-12-07 21:00:42.128 MyApp[1626:60b] 1.2 1.3 1.4
extension Double {
func formatWithDecimalPlaces(decimalPlaces: Int) -> Double {
let formattedString = NSString(format: "%.\(decimalPlaces)f", self) as String
return Double(formattedString)!
}
}
1.3333.formatWithDecimalPlaces(2)
The answers given so far that have received the most votes are relying on NSString methods and are going to require that you have imported Foundation.
Having done that, though, you still have access to NSLog.
So I think the answer to the question, if you are asking how to continue using NSLog in Swift, is simply:
import Foundation
//It will more help, by specify how much decimal Point you want.
let decimalPoint = 2
let floatAmount = 1.10001
let amountValue = String(format: "%0.*f", decimalPoint, floatAmount)
here a "pure" swift solution
var d = 1.234567
operator infix ~> {}
#infix func ~> (left: Double, right: Int) -> String {
if right == 0 {
return "\(Int(left))"
}
var k = 1.0
for i in 1..right+1 {
k = 10.0 * k
}
let n = Double(Int(left*k)) / Double(k)
return "\(n)"
}
println("\(d~>2)")
println("\(d~>1)")
println("\(d~>0)")
Power of extension
extension Double {
var asNumber:String {
if self >= 0 {
var formatter = NSNumberFormatter()
formatter.numberStyle = .NoStyle
formatter.percentSymbol = ""
formatter.maximumFractionDigits = 1
return "\(formatter.stringFromNumber(self)!)"
}
return ""
}
}
let velocity:Float = 12.32982342034
println("The velocity is \(velocity.toNumber)")
Output:
The velocity is 12.3
less typing way:
func fprint(format: String, _ args: CVarArgType...) {
print(NSString(format: format, arguments: getVaList(args)))
}
Plenty of good answers above, but sometimes a pattern is more appropriate than the "%.3f" sort of gobbledygook. Here's my take using a NumberFormatter in Swift 3.
extension Double {
func format(_ pattern: String) -> String {
let formatter = NumberFormatter()
formatter.format = pattern
return formatter.string(from: NSNumber(value: self))!
}
}
let n1 = 0.350, n2 = 0.355
print(n1.format("0.00#")) // 0.35
print(n2.format("0.00#")) // 0.355
Here I wanted 2 decimals to be always shown, but the third only if it wasn't zero.
What about extensions on Double and CGFloat types:
extension Double {
func formatted(_ decimalPlaces: Int?) -> String {
let theDecimalPlaces : Int
if decimalPlaces != nil {
theDecimalPlaces = decimalPlaces!
}
else {
theDecimalPlaces = 2
}
let theNumberFormatter = NumberFormatter()
theNumberFormatter.formatterBehavior = .behavior10_4
theNumberFormatter.minimumIntegerDigits = 1
theNumberFormatter.minimumFractionDigits = 1
theNumberFormatter.maximumFractionDigits = theDecimalPlaces
theNumberFormatter.usesGroupingSeparator = true
theNumberFormatter.groupingSeparator = " "
theNumberFormatter.groupingSize = 3
if let theResult = theNumberFormatter.string(from: NSNumber(value:self)) {
return theResult
}
else {
return "\(self)"
}
}
}
Usage:
let aNumber: Double = 112465848348508.458758344
Swift.print("The number: \(aNumber.formatted(2))")
prints: 112 465 848 348 508.46
You can also create an operator in this way
operator infix <- {}
func <- (format: String, args:[CVarArg]) -> String {
return String(format: format, arguments: args)
}
let str = "%d %.1f" <- [1453, 1.123]
Also with rounding:
extension Float
{
func format(f: String) -> String
{
return NSString(format: "%\(f)f", self)
}
mutating func roundTo(f: String)
{
self = NSString(format: "%\(f)f", self).floatValue
}
}
extension Double
{
func format(f: String) -> String
{
return NSString(format: "%\(f)f", self)
}
mutating func roundTo(f: String)
{
self = NSString(format: "%\(f)f", self).doubleValue
}
}
x = 0.90695652173913
x.roundTo(".2")
println(x) //0.91
use below method
let output = String.localizedStringWithFormat(" %.02f %.02f %.02f", r, g, b)
println(output)
A version of Vincent Guerci's ruby / python % operator, updated for Swift 2.1:
func %(format:String, args:[CVarArgType]) -> String {
return String(format:format, arguments:args)
}
"Hello %#, This is pi : %.2f" % ["World", M_PI]
Swift 4 Xcode 10 Update
extension Double {
var asNumber:String {
if self >= 0 {
let formatter = NumberFormatter()
formatter.numberStyle = .none
formatter.percentSymbol = ""
formatter.maximumFractionDigits = 2
return "\(formatter.string(from: NSNumber(value: self)) ?? "")"
}
return ""
}
}
#infix func ^(left:Double, right: Int) -> NSNumber {
let nf = NSNumberFormatter()
nf.maximumSignificantDigits = Int(right)
return nf.numberFromString(nf.stringFromNumber(left))
}
let r = 0.52264
let g = 0.22643
let b = 0.94837
println("this is a color: \(r^3) \(g^3) \(b^3)")
// this is a color: 0.523 0.226 0.948
I don't know about two decimal places, but here's how you can print floats with zero decimal places, so I'd imagine that can be 2 place, 3, places ... (Note: you must convert CGFloat to Double to pass to String(format:) or it will see a value of zero)
func logRect(r: CGRect, _ title: String = "") {
println(String(format: "[ (%.0f, %.0f), (%.0f, %.0f) ] %#",
Double(r.origin.x), Double(r.origin.y), Double(r.size.width), Double(r.size.height), title))
}
Swift2 example: Screen width of iOS device formatting the Float removing the decimal
print(NSString(format: "Screen width = %.0f pixels", CGRectGetWidth(self.view.frame)))
#Christian Dietrich:
instead of:
var k = 1.0
for i in 1...right+1 {
k = 10.0 * k
}
let n = Double(Int(left*k)) / Double(k)
return "\(n)"
it could also be:
let k = pow(10.0, Double(right))
let n = Double(Int(left*k)) / k
return "\(n)"
[correction:]
Sorry for confusion* - Of course this works with Doubles. I think, most practical (if you want digits to be rounded, not cut off) it would be something like that:
infix operator ~> {}
func ~> (left: Double, right: Int) -> Double {
if right <= 0 {
return round(left)
}
let k = pow(10.0, Double(right))
return round(left*k) / k
}
For Float only, simply replace Double with Float, pow with powf and round with roundf.
Update: I found that it is most practical to use return type Double instead of String. It works the same for String output, i.e.:
println("Pi is roughly \(3.1415926 ~> 3)")
prints: Pi is roughly 3.142
So you can use it the same way for Strings (you can even still write: println(d ~> 2)), but additionally you can also use it to round values directly, i.e.:
d = Double(slider.value) ~> 2
or whatever you need …