Adding integers which are in strings in objective-c - objective-c

For example I have "$100" and "$50" in two strings, I want to add them to get an output "$150".
I know the general method(converting them into integers and adding them), but i am searching for a shorter method which does not call many functions

You can use an NSNumberFormatter to parse the string into a NSNumber, Sum them and then convert back to String :
NSString *strNum1 = "$100";
NSString *strNum2 = "$150";
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterCurrencyStyle];
NSNumber * myFirstNumber = [f numberFromString:strNum1];
NSNumber * mySecNumber = [f numberFromString:strNum2];
NSNumber *sum = [NSNumber numberWithFloat:([myFirstNumber floatValue] + [mySecNumber floatValue])];
NSString * strSum = [f stringFromNumber:sum];

float result = [[fiftyBucks substringFromIndex:1] floatValue] + [[hundredBucks substringFromIndex:1] floatValue];
or use NSScanner, but it will be little longer, but more reliably/safely:
float fifty, hundred, result;
[[NSScaner scannerWithString: fiftyBucks] scanFloat: &fifty];
[[NSScaner scannerWithString: hundredBucks] scanFloat: &hundred];
result = fifty + hundred;

I think you better store the price at CGfloat instead.
showing a string "$100" is a front-end task and calculating the sum of the prices are back end task. These two should be seperated.
If you store the price as a CGFloat, you can simply do the maths.
And when you wanna show that string, juz implement a method.
- (NSString *)priceLabel:(CGFloat) _price {
return [NSString stringWithFormat: #"$.1f", _price];
}
Besides, don't be afraid of making a Front-end Helper model when you code. I put all this kind of minor method in this model as a class method. Wherever you need reuse this method, you can simply import the model.

Related

Objective-C: Separate number right/left of decimal

I am trying to separate the left and right numbers from a float so I can turn each into a string. So for example, 5.11, I need to be able to turn 5 into a string, and 11 into another string.
// from float: 5.11
NSString * leftNumber = #"5";
NSString * rightNumber = #"11";
From this, I can turn 5.11 into 5' 11".
One way:
Use stringWithFormat to convert to string "5.11".
Use componentsSeparatedByString to seperate into an array of "5" and "11".
Combine with stringWithFormat.
You could use NSString stringWithFormat and math functions for that:
float n = 5.11;
NSString * leftNumber = [NSString stringWithFormat:#"%0.0f", truncf(n)];
NSString * rightNumber = [[NSString stringWithFormat:#"%0.2f", fmodf(n, 1.0)] substringFromIndex:2];
NSLog(#"'%#' '%#'", leftNumber, rightNumber);
However, this is not ideal, especially for representing lengths in customary units, because 0.11 ft is not 11 inches. You would be better off representing the length as an integer in the smallest units that you support (say, for example, 1/16-th of an inch) and then convert it to the actual length for display purposes. In this representation 5 ft 11 in would be 5*12*16 + 11*16 = 1136.
You could use a number formatter as such
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
formatter.decimalSeparator = #"'";
formatter.positiveSuffix = #"\"";
formatter.alwaysShowsDecimalSeparator = true;
NSString *numberString = [formatter stringFromNumber:#(5.11)];
// Output : 5'11"

Prevent small negative numbers printing as "-0"

If I do the following in Objective-C:
NSString *result = [NSString stringWithFormat:#"%1.1f", -0.01];
It will give result #"-0.0"
Does anybody know how I can force a result #"0.0" (without the "-") in this case?
EDIT:
I tried using NSNumberFormatter, but it has the same issue. The following also produces #"-0.0":
double value = -0.01;
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMaximumFractionDigits:1];
[numberFormatter setMinimumFractionDigits:1];
NSString *result = [numberFormatter stringFromNumber:[NSNumber numberWithDouble:value]];
I wanted a general solution, independent of the configuration of the number formatter.
I've used a category to add the functionality to NSNumberFormater;
#interface NSNumberFormatter (PreventNegativeZero)
- (NSString *)stringFromNumberWithoutNegativeZero:(NSNumber *)number;
#end
With the implementation:
#implementation NSNumberFormatter (PreventNegativeZero)
- (NSString *)stringFromNumberWithoutNegativeZero:(NSNumber *)number
{
NSString *const string = [self stringFromNumber: number];
NSString *const negZeroString = [self stringFromNumber: [NSNumber numberWithFloat: -0.0f]];
if([string isEqualToString: negZeroString])
{
NSString *const posZeroString = [self stringFromNumber: [NSNumber numberWithFloat: 0.0]];
return posZeroString;
}
return string;
}
#end
How it works
The key feature is to ask the number formatter how it will format -0.0f (i.e., floating point minus zero) as an NSString so that we can detect this and take remedial action.
Why do this? Depending on the formatter configuration, -0.0f could be formatted as: #"-0", #"-0.0", #"-000", #"-0ΒΊC", #"Β£-0.00", #"----0.0", #"(0.0)", #"😑𝟘.β“ͺι›Ά" really, pretty much anything. So, we ask the formatter how it would format -0.0f using the line: NSString *const negZeroString = [self stringFromNumber: [NSNumber numberWithFloat: -0.0f]];
Armed with the undesired -0.0f string, when an arbitrary input number is formatted, it can be tested to see if it is matches the undesirable -0.0f string.
The second important feature is that the number formatter is also asked to supply the replacement positive zero string. This is necessary so that as before, its formatting is respected. This is done with the line: [self stringFromNumber: [NSNumber numberWithFloat: 0.0]]
An optimisation that doesn't work
It's tempting to perform a numerical test yourself for whether the input number will be formatted as the -0.0f string, but this is extremely non trivial (ie, basically impossible in general). This is because the set of numbers that will format to the -0.0f string depend on the configuration of the formatter. If if happens to be rounding to the nearest million, then -5,000f as an input would be formatted as the -0.0f string.
An implementation error to avoid
When input that formats to the -0.0f string is detected, a positive zero equivalent output string is generated using [self stringFromNumber: [NSNumber numberWithFloat: 0.0]]. Note that, specifically:
The code formats the float literal 0.0f and returns it.
The code does not use the negation of the input.
Negating an input of -0.1f would result in formatting 0.1f. Depending on the formatter behaviour, this could be rounded up and result in #"1,000", which you don't want.
Final Note
For what it's worth, the approach / pattern / algorithm used here will translate to other languages and different string formatting APIs.
Use a NSNumberFormatter. In general, NSString formatting should not be used to present data to the user.
EDIT:
As stated in the question, this is not the correct answer. There is a number of solutions. It's easy to check for negative zero because it is defined to be equal to any zero (0.0f == -0.0f) but the actual problem is that a number of other values can be rounded to the negative zero. Instead of catching such values, I suggest postprocessing - a function that will check if the result contains only zero digits (skipping other characters). If yes, remove leading minus sign.
NSString *result = [NSString stringWithFormat:#"%1.1f", -0.01*-1];
If instead of a value you pass an instance you can check:
float myFloat = -0.01;
NSString *result = [NSString stringWithFormat:#"%1.1f", (myFloat<0? myFloat*-1:myFloat)];
Edit:
If you just want 0.0 as positive value:
NSString *result = [NSString stringWithFormat:#"%1.1f",(int)(myFloat*10)<0?myFloat:myFloat*-1];
Convert the number to NSString by taking the float or double value.
Convert the string back to NSNumber.
NSDecimalNumber *num = [NSDecimalNumber decimalNumberWithString:#"-0.00000000008"];
NSString *st2 = [NSString stringWithFormat:#"%0.2f", [num floatValue]];
NSDecimalNumber *result = [NSDecimalNumber decimalNumberWithString:st2]; //returns 0
The NSNumberFormatter has two methods convert from Number to String, and from String to Number. What if we use method (Number) -> String? twice?
public extension NumberFormatter {
func stringWithoutNegativeZero(from number: NSNumber) -> String? {
string(from: number)
.flatMap { [weak self] string in self?.number(from: string) }
.flatMap { [weak self] number in self?.string(from: number) }
}
}

parsing string into different kind of number string

I have a string called realEstateWorth with a value of $12,000,000.
I need this same string to remain a string but for any number (such as the one above) to be displayed as $12 MILLION or $6 MILLION. The point is it needs the words "MILLION" to come after the number.
I know there is nsNumberFormatter that can convert strings into numbers and vice versa but can it do what I need?
If anyone has any ideas or suggestions, it would be much appreciated.
Thank you!
So as I see it, you have two problems:
You have a string representation of something that's actually a number
You (potentially) have a number that you want formatted as a string
So, problem #1:
To convert a string into a number, you use an NSNumberFormatter. You've got a pretty simple case:
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterCurrencyStyle];
NSNumber *n = [f numberFromString:#"$12,000,000"];
// n is 12000000
That was easy! Now problem #2:
This is trickier, because you want a mixed spell-out style. You could consider using an NSNumberFormatter again, but it's not quite right:
[f setNumberStyle:NSNumberFormatterSpellOutStyle];
NSString *s = [f stringFromNumber:n];
// s is "twelve million"
So, we're closer. At this point, you could perhaps maybe do something like:
NSInteger numberOfMillions = [n integerValue] / 1000000;
if (numberOfMillions > 0) {
NSNumber *millions = [NSNumber numberWithInteger:numberOfMillions];
NSString *numberOfMillionsString = [f stringFromNumber:millions]; // "twelve"
[f setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *formattedMillions = [f stringFromNumber:millions]; // "$12.00"
if ([s hasPrefix:numberOfMillionsString]) {
// replace "twelve" with "$12.00"
s = [s stringByReplacingCharactersInRange:NSMakeRange(0, [numberOfMillionsString length]) withString:formattedMillions];
// if this all works, s should be "$12.00 million"
// you can use the -setMaximumFractionDigits: method on NSNumberFormatter to fiddle with the ".00" bit
}
}
However
I don't know how well this would work in anything other than english. CAVEAT IMPLEMENTOR
Worst case scenario, you could implement a category on NSString to implement the behaviour you want.
In the method that you would do in that category you could take an NSNumberFormatter to bring that string to a number and by doing some modulo operation you could define if you need the word Million, or Billion, etc. and put back a string with the modulo for Million or other way you need it to be.
That way you could just call that method on your NSString like this :
NSString *humanReadable = [realEstateWorth myCustomMethodFromMyCategory];
And also.
NSString are immutable, so you can't change it unless you assign a new one to your variable.
I'd recommend storing this value as an NSNumber or a float. Then you could have a method to generate an NSString to display it like:
- (NSString*)numberToCurrencyString:(float)num
{
NSString *postfix = #"";
if (num > 1000000000)
{
num = num / 1000000000;
postfix = #" Billion";
}
else if (num > 1000000)
{
num = num / 1000000;
postfix = #" Million";
}
NSString *currencyString = [NSString stringWithFormat:#"%.0f%#", num, postfix];
return currencyString;
}
Note: Your question states that your input needs to remain a string. That's fine. So you'd need to 1.) first parse the number out of the string and 2.) then reconvert it to a string from a number. I've shown how to do step 2 of this process.

Make a float only show two decimal places

I have the value 25.00 in a float, but when I print it on screen it is 25.0000000.
How can I display the value with only two decimal places?
It is not a matter of how the number is stored, it is a matter of how you are displaying it. When converting it to a string you must round to the desired precision, which in your case is two decimal places.
E.g.:
NSString* formattedNumber = [NSString stringWithFormat:#"%.02f", myFloat];
%.02f tells the formatter that you will be formatting a float (%f) and, that should be rounded to two places, and should be padded with 0s.
E.g.:
%f = 25.000000
%.f = 25
%.02f = 25.00
Here are few corrections-
//for 3145.559706
Swift 3
let num: CGFloat = 3145.559706
print(String(format: "%f", num)) = 3145.559706
print(String(format: "%.f", num)) = 3145
print(String(format: "%.1f", num)) = 3145.6
print(String(format: "%.2f", num)) = 3145.56
print(String(format: "%.02f", num)) = 3145.56 // which is equal to #"%.2f"
print(String(format: "%.3f", num)) = 3145.560
print(String(format: "%.03f", num)) = 3145.560 // which is equal to #"%.3f"
Obj-C
#"%f" = 3145.559706
#"%.f" = 3146
#"%.1f" = 3145.6
#"%.2f" = 3145.56
#"%.02f" = 3145.56 // which is equal to #"%.2f"
#"%.3f" = 3145.560
#"%.03f" = 3145.560 // which is equal to #"%.3f"
and so on...
You can also try using NSNumberFormatter:
NSNumberFormatter* nf = [[[NSNumberFormatter alloc] init] autorelease];
nf.positiveFormat = #"0.##";
NSString* s = [nf stringFromNumber: [NSNumber numberWithFloat: myFloat]];
You may need to also set the negative format, but I think it's smart enough to figure it out.
I made a swift extension based on above answers
extension Float {
func round(decimalPlace:Int)->Float{
let format = NSString(format: "%%.%if", decimalPlace)
let string = NSString(format: format, self)
return Float(atof(string.UTF8String))
}
}
usage:
let floatOne:Float = 3.1415926
let floatTwo:Float = 3.1425934
print(floatOne.round(2) == floatTwo.round(2))
// should be true
In Swift Language, if you want to show you need to use it in this way. To assign double value in UITextView, for example:
let result = 23.954893
resultTextView.text = NSString(format:"%.2f", result)
If you want to show in LOG like as objective-c does using NSLog(), then in Swift Language you can do this way:
println(NSString(format:"%.2f", result))
IN objective-c, if you are dealing with regular char arrays (instead of pointers to NSString) you could also use:
printf("%.02f", your_float_var);
OTOH, if what you want is to store that value on a char array you could use:
sprintf(your_char_ptr, "%.02f", your_float_var);
The problem with all the answers is that multiplying and then dividing results in precision issues because you used division. I learned this long ago from programming on a PDP8.
The way to resolve this is:
return roundf(number * 100) * .01;
Thus 15.6578 returns just 15.66 and not 15.6578999 or something unintended like that.
What level of precision you want is up to you. Just don't divide the product, multiply it by the decimal equivalent.
No funny String conversion required.
in objective -c is u want to display float value in 2 decimal number then pass argument indicating how many decimal points u want to display
e.g 0.02f will print 25.00
0.002f will print 25.000
Here's some methods to format dynamically according to a precision:
+ (NSNumber *)numberFromString:(NSString *)string
{
if (string.length) {
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
f.numberStyle = NSNumberFormatterDecimalStyle;
return [f numberFromString:string];
} else {
return nil;
}
}
+ (NSString *)stringByFormattingString:(NSString *)string toPrecision:(NSInteger)precision
{
NSNumber *numberValue = [self numberFromString:string];
if (numberValue) {
NSString *formatString = [NSString stringWithFormat:#"%%.%ldf", (long)precision];
return [NSString stringWithFormat:formatString, numberValue.floatValue];
} else {
/* return original string */
return string;
}
}
e.g.
[TSPAppDelegate stringByFormattingString:#"2.346324" toPrecision:4];
=> 2.3453
[TSPAppDelegate stringByFormattingString:#"2.346324" toPrecision:0];
=> 2
[TSPAppDelegate stringByFormattingString:#"2.346324" toPrecision:2];
=> 2.35 (round up)
Another method for Swift (without using NSString):
let percentage = 33.3333
let text = String.localizedStringWithFormat("%.02f %#", percentage, "%")
P.S. this solution is not working with CGFloat type only tested with Float & Double
Use NSNumberFormatter with maximumFractionDigits as below:
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.maximumFractionDigits = 2;
NSLog(#"%#", [formatter stringFromNumber:[NSNumber numberWithFloat:12.345]]);
And you will get 12.35
If you need to float value as well:
NSString* formattedNumber = [NSString stringWithFormat:#"%.02f", myFloat];
float floatTwoDecimalDigits = atof([formattedNumber UTF8String]);
lblMeter.text=[NSString stringWithFormat:#"%.02f",[[dic objectForKey:#"distance"] floatValue]];

How to add two NSNumber objects?

Now this must be easy, but how can sum two NSNumber? Is like:
[one floatValue] + [two floatValue]
or exist a better way?
There is not really a better way, but you really should not be doing this if you can avoid it. NSNumber exists as a wrapper to scalar numbers so you can store them in collections and pass them polymorphically with other NSObjects. They are not really used to store numbers in actual math. If you do math on them it is much slower than performing the operation on just the scalars, which is probably why there are no convenience methods for it.
For example:
NSNumber *sum = [NSNumber numberWithFloat:([one floatValue] + [two floatValue])];
Is blowing at a minimum 21 instructions on message dispatches, and however much code the methods take to unbox the and rebox the values (probably a few hundred) to do 1 instruction worth of math.
So if you need to store numbers in dicts use an NSNumber, if you need to pass something that might be a number or string into a function use an NSNumber, but if you just want to do math stick with scalar C types.
NSDecimalNumber (subclass of NSNumber) has all the goodies you are looking for:
– decimalNumberByAdding:
– decimalNumberBySubtracting:
– decimalNumberByMultiplyingBy:
– decimalNumberByDividingBy:
– decimalNumberByRaisingToPower:
...
If computing performance is of interest, then convert to C++ array std::vector or like.
Now I never use C-Arrays anymore; it is too easy to crash using a wrong index or pointer. And very tedious to pair every new [] with delete[].
You can use
NSNumber *sum = #([first integerValue] + [second integerValue]);
Edit:
As observed by ohho, this example is for adding up two NSNumber instances that hold integer values. If you want to add up two NSNumber's that hold floating-point values, you should do the following:
NSNumber *sum = #([first floatValue] + [second floatValue]);
The current top-voted answer is going to lead to hard-to-diagnose bugs and loss of precision due to the use of floats. If you're doing number operations on NSNumber values, you should convert to NSDecimalNumber first and perform operations with those objects instead.
From the documentation:
NSDecimalNumber, an immutable subclass of NSNumber, provides an object-oriented wrapper for doing base-10 arithmetic. An instance can represent any number that can be expressed as mantissa x 10^exponent where mantissa is a decimal integer up to 38 digits long, and exponent is an integer from –128 through 127.
Therefore, you should convert your NSNumber instances to NSDecimalNumbers by way of [NSNumber decimalValue], perform whatever arithmetic you want to, then assign back to an NSNumber when you're done.
In Objective-C:
NSDecimalNumber *a = [NSDecimalNumber decimalNumberWithDecimal:one.decimalValue]
NSDecimalNumber *b = [NSDecimalNumber decimalNumberWithDecimal:two.decimalValue]
NSNumber *result = [a decimalNumberByAdding:b]
In Swift 3:
let a = NSDecimalNumber(decimal: one.decimalValue)
let b = NSDecimalNumber(decimal: two.decimalValue)
let result: NSNumber = a.adding(b)
Why not use NSxEpression?
NSNumber *x = #(4.5), *y = #(-2);
NSExpression *ex = [NSExpression expressionWithFormat:#"(%# + %#)", x, y];
NSNumber *result = [ex expressionValueWithObject:nil context:nil];
NSLog(#"%#",result); // will print out "2.5"
You can also build an NSExpression that can be reused to evaluate with different arguments, like this:
NSExpression *expr = [NSExpression expressionWithFormat: #"(X+Y)"];
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:x, #"X", y, #"Y", nil];
NSLog(#"%#", [expr expressionValueWithObject:parameters context:nil]);
For instance, we can loop evaluating the same parsed expression, each time with a different "Y" value:
for (float f=20; f<30; f+=2.0) {
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:x, #"X", #(f), #"Y", nil];
NSLog(#"%#", [expr expressionValueWithObject:parameters context:nil]);
}
In Swift you can get this functionality by using the Bolt_Swift library https://github.com/williamFalcon/Bolt_Swift.
Example:
var num1 = NSNumber(integer: 20)
var num2 = NSNumber(integer: 25)
print(num1+num2) //prints 45