iOS将大数字转换为更小的格式
如何将所有超过3位数的数字转换为4位或更less的数字?
这正是我的意思:
10345 = 10.3k 10012 = 10k 123546 = 123.5k 4384324 = 4.3m
舍入不是完全重要的,但另外一个好处。
我已经看了NSNumberFormatter,但还没有find适当的解决scheme,我还没有find一个合适的解决scheme在这里。 任何帮助非常感谢,谢谢!
-(NSString*) suffixNumber:(NSNumber*)number { if (!number) return @""; long long num = [number longLongValue]; int s = ( (num < 0) ? -1 : (num > 0) ? 1 : 0 ); NSString* sign = (s == -1 ? @"-" : @"" ); num = llabs(num); if (num < 1000) return [NSString stringWithFormat:@"%@%lld",sign,num]; int exp = (int) (log10l(num) / 3.f); //log10l(1000)); NSArray* units = @[@"K",@"M",@"G",@"T",@"P",@"E"]; return [NSString stringWithFormat:@"%@%.1f%@",sign, (num / pow(1000, exp)), [units objectAtIndex:(exp-1)]]; }
样本用法
NSLog(@"%@",[self suffixNumber:@100]); // 100 NSLog(@"%@",[self suffixNumber:@1000]); // 1.0K NSLog(@"%@",[self suffixNumber:@1500]); // 1.5K NSLog(@"%@",[self suffixNumber:@24000]); // 24.0K NSLog(@"%@",[self suffixNumber:@99900]); // 99.9K NSLog(@"%@",[self suffixNumber:@99999]); // 100.0K NSLog(@"%@",[self suffixNumber:@109999]); // 110.0K NSLog(@"%@",[self suffixNumber:@5109999]); // 5.1M NSLog(@"%@",[self suffixNumber:@8465445223]); // 8.5G NSLog(@"%@",[self suffixNumber:[NSNumber numberWithInt:-120]]); // -120 NSLog(@"%@",[self suffixNumber:[NSNumber numberWithLong:-5000000]]); // -5.0M NSLog(@"%@",[self suffixNumber:[NSNumber numberWithDouble:-3.5f]]); // -3 NSLog(@"%@",[self suffixNumber:[NSNumber numberWithDouble:-4000.63f]]); // -4.0K
[ 更新 ]
下面的Swift版本:
func suffixNumber(number:NSNumber) -> NSString { var num:Double = number.doubleValue; let sign = ((num < 0) ? "-" : "" ); num = fabs(num); if (num < 1000.0){ return "\(sign)\(num)"; } let exp:Int = Int(log10(num) / 3.0 ); //log10(1000)); let units:[String] = ["K","M","G","T","P","E"]; let roundedNum:Double = round(10 * num / pow(1000.0,Double(exp))) / 10; return "\(sign)\(roundedNum)\(units[exp-1])"; }
样本用法
print(self.suffixNumber(NSNumber(long: 100))); // 100.0 print(self.suffixNumber(NSNumber(long: 1000))); // 1.0K print(self.suffixNumber(NSNumber(long: 1500))); // 1.5K print(self.suffixNumber(NSNumber(long: 24000))); // 24.0K print(self.suffixNumber(NSNumber(longLong: 99900))); // 99.9K print(self.suffixNumber(NSNumber(longLong: 99999))); // 100.0K print(self.suffixNumber(NSNumber(longLong: 109999))); // 110.0K print(self.suffixNumber(NSNumber(longLong: 5109999))); // 5.1K print(self.suffixNumber(NSNumber(longLong: 8465445223))); // 8.5G print(self.suffixNumber(NSNumber(long: -120))); // -120.0 print(self.suffixNumber(NSNumber(longLong: -5000000))); // -5.0M print(self.suffixNumber(NSNumber(float: -3.5))); // -3.5 print(self.suffixNumber(NSNumber(float: -4000.63))); // -4.0K
希望能帮助到你
我有同样的问题,最终使用凯尔的方法,但不幸的是,当数字120000使用,显示12K而不是120K ,我需要显示小数字,如:1.1K,而不是舍入到1K。
所以这里是我从Kyle原来的想法编辑:
Results: [self abbreviateNumber:987] ---> 987 [self abbreviateNumber:1200] ---> 1.2K [self abbreviateNumber:12000] ----> 12K [self abbreviateNumber:120000] ----> 120K [self abbreviateNumber:1200000] ---> 1.2M [self abbreviateNumber:1340] ---> 1.3K [self abbreviateNumber:132456] ----> 132.5K -(NSString *)abbreviateNumber:(int)num { NSString *abbrevNum; float number = (float)num; //Prevent numbers smaller than 1000 to return NULL if (num >= 1000) { NSArray *abbrev = @[@"K", @"M", @"B"]; for (int i = abbrev.count - 1; i >= 0; i--) { // Convert array index to "1000", "1000000", etc int size = pow(10,(i+1)*3); if(size <= number) { // Removed the round and dec to make sure small numbers are included like: 1.1K instead of 1K number = number/size; NSString *numberString = [self floatToString:number]; // Add the letter for the abbreviation abbrevNum = [NSString stringWithFormat:@"%@%@", numberString, [abbrev objectAtIndex:i]]; } } } else { // Numbers like: 999 returns 999 instead of NULL abbrevNum = [NSString stringWithFormat:@"%d", (int)number]; } return abbrevNum; } - (NSString *) floatToString:(float) val { NSString *ret = [NSString stringWithFormat:@"%.1f", val]; unichar c = [ret characterAtIndex:[ret length] - 1]; while (c == 48) { // 0 ret = [ret substringToIndex:[ret length] - 1]; c = [ret characterAtIndex:[ret length] - 1]; //After finding the "." we know that everything left is the decimal number, so get a substring excluding the "." if(c == 46) { // . ret = [ret substringToIndex:[ret length] - 1]; } } return ret; }
我希望这可以帮助你们。
在这里我的版本! 感谢以前的答案。 这个版本的目标是:
- 因为less数细节比较重要,所以要有更好的门槛控制
- 使用尽可能多的
NSNumberFormatter
来避免位置问题(如逗号而不是法文中的点) - 避免“.0”和四舍五入的数字,这可以使用
NSNumberFormatterRoundingMode
自定义
您可以使用所有美妙的NSNumberFormatter
选项来满足您的需求,请参阅NSNumberFormatter类参考
代码( gist ):
extension Int { func formatUsingAbbrevation () -> String { let numFormatter = NSNumberFormatter() typealias Abbrevation = (threshold:Double, divisor:Double, suffix:String) let abbreviations:[Abbrevation] = [(0, 1, ""), (1000.0, 1000.0, "K"), (100_000.0, 1_000_000.0, "M"), (100_000_000.0, 1_000_000_000.0, "B")] // you can add more ! let startValue = Double (abs(self)) let abbreviation:Abbrevation = { var prevAbbreviation = abbreviations[0] for tmpAbbreviation in abbreviations { if (startValue < tmpAbbreviation.threshold) { break } prevAbbreviation = tmpAbbreviation } return prevAbbreviation } () let value = Double(self) / abbreviation.divisor numFormatter.positiveSuffix = abbreviation.suffix numFormatter.negativeSuffix = abbreviation.suffix numFormatter.allowsFloats = true numFormatter.minimumIntegerDigits = 1 numFormatter.minimumFractionDigits = 0 numFormatter.maximumFractionDigits = 1 return numFormatter.stringFromNumber(NSNumber (double:value))! } } let testValue:[Int] = [598, -999, 1000, -1284, 9940, 9980, 39900, 99880, 399880, 999898, 999999, 1456384, 12383474] testValue.forEach() { print ("Value : \($0) -> \($0.formatUsingAbbrevation ())") }
结果:
Value : 598 -> 598 Value : -999 -> -999 Value : 1000 -> 1K Value : -1284 -> -1.3K Value : 9940 -> 9.9K Value : 9980 -> 10K Value : 39900 -> 39.9K Value : 99880 -> 99.9K Value : 399880 -> 0.4M Value : 999898 -> 1M Value : 999999 -> 1M Value : 1456384 -> 1.5M Value : 12383474 -> 12.4M
FlávioJ Vieira Caetano的答案转换为Swift 3.0
extension Int { var abbreviated: String { let abbrev = "KMBTPE" return abbrev.characters.enumerated().reversed().reduce(nil as String?) { accum, tuple in let factor = Double(self) / pow(10, Double(tuple.0 + 1) * 3) let format = (factor.truncatingRemainder(dividingBy: 1) == 0 ? "%.0f%@" : "%.1f%@") return accum ?? (factor > 1 ? String(format: format, factor, String(tuple.1)) : nil) } ?? String(self) } }
我遇到了一个类似的问题,试图在Shinobi Charts中格式化Y轴值。 它需要使用NSNumberFormatter,所以我最终想出了这个
NSNumberFormatter *numFormatter = [[NSNumberFormatter alloc] init]; [numFormatter setPositiveFormat:@"0M"]; [numFormatter setMultiplier:[NSNumber numberWithDouble:0.000001]];
获取格式化的值
NSString *formattedNumber = [numFormatter stringFromNumber:[NSNumber numberWithInteger:4000000]]; //@"4M"
这个解决scheme不包括四舍五入,但如果你(或其他人)只是需要一些简单的东西,这可以工作。 如果您需要的是千位而不是百位,您可以在setPostiveFormat方法中将“M”更改为“K”,并将乘数中的NSNumber值更改为0.001。
这里有两个方法,我已经想出了这个工作,以产生预期的效果。 这也将自动收起来。 这也将通过传递int dec指定总共有多less个数字。
此外,在float to string方法中,可以将@"%.1f"
更改为@"%.2f"
, @"%.3f"
等,以告诉它在小数点后显示多less个可见小数。
For Example: 52935 ---> 53K 52724 ---> 53.7K -(NSString *)abbreviateNumber:(int)num withDecimal:(int)dec { NSString *abbrevNum; float number = (float)num; NSArray *abbrev = @[@"K", @"M", @"B"]; for (int i = abbrev.count - 1; i >= 0; i--) { // Convert array index to "1000", "1000000", etc int size = pow(10,(i+1)*3); if(size <= number) { // Here, we multiply by decPlaces, round, and then divide by decPlaces. // This gives us nice rounding to a particular decimal place. number = round(number*dec/size)/dec; NSString *numberString = [self floatToString:number]; // Add the letter for the abbreviation abbrevNum = [NSString stringWithFormat:@"%@%@", numberString, [abbrev objectAtIndex:i]]; NSLog(@"%@", abbrevNum); } } return abbrevNum; } - (NSString *) floatToString:(float) val { NSString *ret = [NSString stringWithFormat:@"%.1f", val]; unichar c = [ret characterAtIndex:[ret length] - 1]; while (c == 48 || c == 46) { // 0 or . ret = [ret substringToIndex:[ret length] - 1]; c = [ret characterAtIndex:[ret length] - 1]; } return ret; }
希望这可以帮助任何需要它的人!
在尝试了几个这样的解决scheme之后,Luca laco似乎有了最接近的地方,但是我已经对他的方法做了一些修改,以便更好地控制多less数字出现(也就是说,如果你想让120.3K变短,你可以限制到120K)。 此外,我添加了一个额外的步骤,确保999,999的数字不会显示为1000.0K,而是1.0M。
/* With "onlyShowDecimalPlaceForNumbersUnder" = 10: Original number: 598 - Result: 598 Original number: 1000 - Result: 1.0K Original number: 1284 - Result: 1.3K Original number: 9980 - Result: 10K Original number: 39900 - Result: 40K Original number: 99880 - Result: 100K Original number: 999898 - Result: 1.0M Original number: 999999 - Result: 1.0M Original number: 1456384 - Result: 1.5M Original number: 12383474 - Result: 12M */ - (NSString *)suffixNumber:(NSNumber *)number { if (!number) return @""; long long num = [number longLongValue]; if (num < 1000) return [NSString stringWithFormat:@"%lld",num]; int exp = (int) (log(num) / log(1000)); NSArray * units = @[@"K",@"M",@"G",@"T",@"P",@"E"]; int onlyShowDecimalPlaceForNumbersUnder = 10; // Either 10, 100, or 1000 (ie 10 means 12.2K would change to 12K, 100 means 120.3K would change to 120K, 1000 means 120.3K stays as is) NSString *roundedNumStr = [NSString stringWithFormat:@"%.1f", (num / pow(1000, exp))]; int roundedNum = [roundedNumStr integerValue]; if (roundedNum >= onlyShowDecimalPlaceForNumbersUnder) { roundedNumStr = [NSString stringWithFormat:@"%.0f", (num / pow(1000, exp))]; roundedNum = [roundedNumStr integerValue]; } if (roundedNum >= 1000) { // This fixes a number like 999,999 from displaying as 1000K by changing it to 1.0M exp++; roundedNumStr = [NSString stringWithFormat:@"%.1f", (num / pow(1000, exp))]; } NSString *result = [NSString stringWithFormat:@"%@%@", roundedNumStr, [units objectAtIndex:(exp-1)]]; NSLog(@"Original number: %@ - Result: %@", number, result); return result; }
我知道已经有很多的答案和不同的方式,但是这是我用一个更加实用的方法解决的:
extension Int { var abbreviated: String { let abbrev = "KMBTPE" return abbrev.characters .enumerated() .reversed() .reduce(nil as String?) { accum, tuple in let factor = Double(self) / pow(10, Double(tuple.0 + 1) * 3) let format = (factor - floor(factor) == 0 ? "%.0f%@" : "%.1f%@") return accum ?? (factor >= 1 ? String(format: format, factor, String(tuple.1)) : nil) } ?? String(self) } }
Swift版本
从Objective-C版本直接翻译
func abbreviateNumber(num: NSNumber) -> NSString { var ret: NSString = "" let abbrve: [String] = ["K", "M", "B"] var floatNum = num.floatValue if floatNum > 1000 { for i in 0..<abbrve.count { let size = pow(10.0, (Float(i) + 1.0) * 3.0) println("\(size) \(floatNum)") if (size <= floatNum) { let num = floatNum / size let str = floatToString(num) ret = NSString(format: "%@%@", str, abbrve[i]) } } } else { ret = NSString(format: "%d", Int(floatNum)) } return ret } func floatToString(val: Float) -> NSString { var ret = NSString(format: "%.1f", val) var c = ret.characterAtIndex(ret.length - 1) while c == 48 { ret = ret.substringToIndex(ret.length - 1) c = ret.characterAtIndex(ret.length - 1) if (c == 46) { ret = ret.substringToIndex(ret.length - 1) } } return ret } abbreviateNumber(123) abbreviateNumber(12503) abbreviateNumber(12934203) abbreviateNumber(12234200003) abbreviateNumber(92234203) abbreviateNumber(9223.3)
更新了快速转换的答案
extension Int { func abbreviateNumber() -> String { func floatToString(val: Float) -> String { var ret: NSString = NSString(format: "%.1f", val) let c = ret.characterAtIndex(ret.length - 1) if c == 46 { ret = ret.substringToIndex(ret.length - 1) } return ret as String } var abbrevNum = "" var num: Float = Float(self) if num >= 1000 { var abbrev = ["K","M","B"] for var i = abbrev.count-1; i >= 0; i-- { let sizeInt = pow(Double(10), Double((i+1)*3)) let size = Float(sizeInt) if size <= num { num = num/size var numStr: String = floatToString(num) if numStr.hasSuffix(".0") { let startIndex = numStr.startIndex.advancedBy(0) let endIndex = numStr.endIndex.advancedBy(-2) let range = startIndex..<endIndex numStr = numStr.substringWithRange( range ) } let suffix = abbrev[i] abbrevNum = numStr+suffix } } } else { abbrevNum = "\(num)" let startIndex = abbrevNum.startIndex.advancedBy(0) let endIndex = abbrevNum.endIndex.advancedBy(-2) let range = startIndex..<endIndex abbrevNum = abbrevNum.substringWithRange( range ) } return abbrevNum } }
extension Int { func abbreviateNumber() -> String { func floatToString(val: Float) -> String { var ret: NSString = NSString(format: "%.1f", val) var c = ret.characterAtIndex(ret.length - 1) if c == 46 { ret = ret.substringToIndex(ret.length - 1) } return ret as String } var abbrevNum = "" var num: Float = Float(self) if num >= 1000 { var abbrev = ["K","M","B"] for var i = abbrev.count-1; i >= 0; i-- { var sizeInt = pow(Double(10), Double((i+1)*3)) var size = Float(sizeInt) if size <= num { num = num/size var numStr: String = floatToString(num) if numStr.hasSuffix(".0") { numStr = numStr.substringToIndex(advance(numStr.startIndex,count(numStr)-2)) } var suffix = abbrev[i] abbrevNum = numStr+suffix } } } else { abbrevNum = "\(num)" if abbrevNum.hasSuffix(".0") { abbrevNum = abbrevNum.substringToIndex(advance(abbrevNum.startIndex, count(abbrevNum)-2)) } } return abbrevNum } }
如果您对格式化字节数感兴趣, Mattt Thompson的这篇文章演示了如何使用iOS / OSX内置的NSByteCountFormatter
还有能量 , 质量 , 长度和其他一些内置的格式化程序。
关键在于,对于大多数常见的单位,您不需要编写任何自定义代码,因为苹果已经为您提供了繁琐的工作。 检查NS [SomeUnit]格式化程序的在线参考,例如MKDistanceFormatter
, NSDateIntervalFormatter
或NSDateFormatter
等…
你可以使用这个简单的function,这个想法很容易理解
-(NSString*) suffixNumber:(NSNumber*)number double value = [number doubleValue]; NSUInteger index = 0; NSArray *suffixArray = @[@"", @"K", @"M", @"B", @"T", @"P", @"E"]; while ((value/1000) >= 1){ value = value/1000; index++; } //3 line of code below for round doubles to 1 digit NSNumberFormatter *fmt = [[NSNumberFormatter alloc] init]; [fmt setMaximumFractionDigits:1]; NSString *valueWith1Digit = [fmt stringFromNumber:[NSNumber numberWithFloat:value]]; NSString *svalue = [NSString stringWithFormat:@"%@%@",valueWith1Digit, [suffixArray objectAtIndex:index]]; return svalue; }
testing
NSLog(@"%@",[self suffixNumber:@100]); // 100 NSLog(@"%@",[self suffixNumber:@1000]); // 1K NSLog(@"%@",[self suffixNumber:@10345]); // 10.3K NSLog(@"%@",[self suffixNumber:@10012]); // 10K NSLog(@"%@",[self suffixNumber:@123456]); // 123.5K NSLog(@"%@",[self suffixNumber:@4384324]); // 4.4M NSLog(@"%@",[self suffixNumber:@10000000]) // 10M
这里是Luca Iaco与Swift 4 合作的更新版本
func suffixNumber(number: NSNumber) -> String { var num:Double = number.doubleValue let sign = ((num < 0) ? "-" : "" ) num = fabs(num) if (num < 1000.0) { return "\(sign)\(num)" } let exp: Int = Int(log10(num) / 3.0) let units: [String] = ["K","M","G","T","P","E"] let roundedNum: Double = round(10 * num / pow(1000.0,Double(exp))) / 10 return "\(sign)\(roundedNum)\(units[exp-1])"; }
下面的方法可以处理正数和负数,这与大多数解决scheme不同。
它甚至适用于货币。
BOOL isCurrency = YES; // Make it YES / NO depending upon weather your input value belongs to a revenue figure or a normal value. double value = XXX ; // where 'XXX' is your input value NSString *formattedValue = @""; int decimalPlaces = 1; // number of decimal places (precision) that you want. float multiplier; // Enumerate number abbreviations NSArray *abbrevations = @[@"", @"k", @"m", @"b", @"t" ]; // Go through the array backwards, so we do the largest first int index; for (index = abbrevations.count-1; index >= 0; index--) { multiplier = pow(10, decimalPlaces); // Convert array index to "1000", "1000000", etc double size = pow(10, index*3); // If the number is bigger or equal do the abbreviation if(size <= fabs(round(value))) { // Here, we multiply by multiplier, round, and then divide by multiplier. // This gives us nice rounding to a particular decimal place. value = round(value * multiplier / size) / multiplier; // We are done... stop break; } } if (index<0) { // Note: - To handle special case where x is our input number, -0.5 > x < 0.5 value = 0; index++; } NSString *stringFormat = nil; // Add the letter for the abbreviation if (isCurrency) { if (value >=0) { stringFormat = [NSString stringWithFormat:@"$%%.%0df%@", decimalPlaces, abbrevations[index]]; } else { // Note: - To take care of extra logic where '$' symbol comes after '-' symbol for negative currency. stringFormat = [NSString stringWithFormat:@"-$%%.%df%@", decimalPlaces, abbrevations[index]]; value = -value; } } else { stringFormat = [NSString stringWithFormat:@"%%.%0df%@", decimalPlaces, abbrevations[index]]; } formattedValue = [NSString stringWithFormat:stringFormat, value];
输出如下
In Currency mode '999' ---- '$999.0' '999.9' ---- '$1.0k' '999999.9' ---- '$1.0m' '-1000.1' ---- '-$1.0k' '-0.9' ---- '-$0.9' In Number mode '999' ---- '999.0' '999.9' ---- '1.0k' '1' ---- '1.0' '9999' ---- '10.0k' '99999.89999999999' ---- '100.0k' '999999.9' ---- '1.0m' '-1' ---- '-1.0' '-1000.1' ---- '-1.0k' '5109999' ---- '5.1m' '-5109999' ---- '-5.1m' '999999999.9' ---- '1.0b' '0.1' ---- '0.0' '0' ---- '0.0' '-0.1' ---- '0.0' '-0.9' ---- '-0.9'
我已经从@Pandiyan Cool共享的链接创build了基于@Kyle Begeman的原创灵感的上述方法。 感谢@Jeff B从以下链接获取Javascript中的初始代码。 有没有办法将数字整理成适合读者的格式? (如$ 1.1k)
Swift 2.2作为双扩展:
extension Double { var suffixNumber : String { get { var num = self let sign = ((num < 0) ? "-" : "" ) num = fabs(num) if (num < 1000.0){ return "\(sign)\(num)" } let exp:Int = Int(log10(num) / 3.0 ) let units:[String] = ["K","M","G","T","P","E"] let roundedNum = round(10 * num / pow(1000.0,Double(exp))) / 10 return "\(sign)\(roundedNum)\(units[exp-1])" } } }
我用gbitaudeau的答案来做这个NSNumberFormatter的Objective-C类,我在我们的项目中使用( Vero.co )。 这里的NSNumberFormatter实例只为整个项目创build一次。
@implementation NSNumberFormatter (Abbreviation) + (NSString*) abbreviatedStringFromNumber:(NSNumber*) number { static dispatch_once_t pred; static NSNumberFormatter* __abbrFormatter = nil; static NSArray<NSDictionary*> * __abbreviations = nil; dispatch_once(&pred, ^{ __abbrFormatter = [[NSNumberFormatter alloc] init]; __abbrFormatter.numberStyle = NSNumberFormatterDecimalStyle; __abbrFormatter.usesGroupingSeparator = YES; __abbrFormatter.allowsFloats = YES; __abbrFormatter.minimumIntegerDigits = 1; __abbrFormatter.minimumFractionDigits = 0; __abbrFormatter.maximumFractionDigits = 2; __abbreviations = @[@{@"threshold":@(0.0), @"divisor":@(1.0), @"suffix":@""}, @{@"threshold":@(1000.0), @"divisor":@(1000.0), @"suffix":@"K"}, @{@"threshold":@(1000000.0), @"divisor":@(1000000.0), @"suffix":@"M"}]; }); double startValue = ABS([number doubleValue]); NSDictionary* abbreviation = __abbreviations[0]; for (NSDictionary* tmpAbbr in __abbreviations) { if (startValue < [tmpAbbr[@"threshold"] doubleValue]) { break; } abbreviation = tmpAbbr; } double value = [number doubleValue] / [abbreviation[@"divisor"] doubleValue]; [__abbrFormatter setLocale:[NSLocale currentLocale]]; //user might change locale while the app is sleeping [__abbrFormatter setPositiveSuffix:abbreviation[@"suffix"]]; [__abbrFormatter setNegativeSuffix:abbreviation[@"suffix"]]; return [__abbrFormatter stringFromNumber:@(value)]; } @end
你现在可以这样称呼它
[NSNumberFormatter abbreviatedStringFromNumber:@(N)];
为什么你们这么难?
它可以像这样简单:
-(NSString *)friendlyNumber:(long long)num{ NSString *stringNumber; if (num < 1000) { stringNumber = [NSString stringWithFormat:@"%lld", num]; }else if(num < 1000000){ float newNumber = floor(num / 100) / 10.0; stringNumber = [NSString stringWithFormat:@"%.1fK", newNumber]; }else{ float newNumber = floor(num / 100000) / 10.0; stringNumber = [NSString stringWithFormat:@"%.1fM", newNumber]; } return stringNumber; }