【问题标题】:Swift 2.0 Format 1000's into a friendly K'sSwift 2.0 将 1000 格式化为友好的 K
【发布时间】:2016-04-02 17:58:05
【问题描述】:

我正在尝试编写一个函数来将成千上万的数字呈现为 K 和 M 例如:

1000 = 1k
1100 = 1.1k
15000 = 15k
115000 = 115k
1000000 = 1m

这是我到目前为止的地方:

func formatPoints(num: Int) -> String {
    let newNum = String(num / 1000)
    var newNumString = "\(num)"
    if num > 1000 && num < 1000000 {
        newNumString = "\(newNum)k"
    } else if num > 1000000 {
        newNumString = "\(newNum)m"
    }

    return newNumString
}

formatPoints(51100) // THIS RETURNS 51K instead of 51.1K

如何让这个功能工作,我错过了什么?

【问题讨论】:

  • 你正在做整数除法,只是把余数扔掉。你可能想转换成双打来做你的数学。
  • 使用NSByteCountFormatter 代替您自己的代码。
  • 我不会很快,但从 Obj-C 的角度来看,我会说您使用 Int 值作为输入,所以 num / 1000 可能不会返回任何小数。
  • 看看stackoverflow.com/questions/35854069/…(以及链接到的线程)。

标签: ios swift numbers swift2 format


【解决方案1】:
extension Int {
    var roundedWithAbbreviations: String {
        let number = Double(self)
        let thousand = number / 1000
        let million = number / 1000000
        if million >= 1.0 {
            return "\(round(million*10)/10)M"
        }
        else if thousand >= 1.0 {
            return "\(round(thousand*10)/10)K"
        }
        else {
            return "\(self)"
        }
    }
}

print(11.roundedWithAbbreviations)          // "11"
print(11111.roundedWithAbbreviations)       // "11.1K"
print(11111111.roundedWithAbbreviations)    // "11.1 M"

【讨论】:

    【解决方案2】:
    func formatPoints(num: Double) ->String{
        let thousandNum = num/1000
        let millionNum = num/1000000
        if num >= 1000 && num < 1000000{
            if(floor(thousandNum) == thousandNum){
                return("\(Int(thousandNum))k")
            }
            return("\(thousandNum.roundToPlaces(1))k")
        }
        if num > 1000000{
            if(floor(millionNum) == millionNum){
                return("\(Int(thousandNum))k")
            }
            return ("\(millionNum.roundToPlaces(1))M")
        }
        else{
            if(floor(num) == num){
                return ("\(Int(num))")
            }
            return ("\(num)")
        }
    
    }
    
    extension Double {
        /// Rounds the double to decimal places value
        func roundToPlaces(places:Int) -> Double {
            let divisor = pow(10.0, Double(places))
            return round(self * divisor) / divisor
        }
    }
    

    如果数字是整数,更新后的代码现在不应返回 .0。例如,现在应该输出 1k 而不是 1.0k。我只是检查了 double 和它的 floor 是否相同。

    我在这个问题中找到了双重扩展名: Rounding a double value to x number of decimal places in swift

    【讨论】:

    • 试过了,但是当数字低于 1000 时,它会返回 .0,所以 916 会变成 916.0
    • 如果数字小于 1000,您只需添加一个 if 语句,然后运行与我运行的相同的检查。
    • 我刚刚更新了对 1000 以下数字也适用的答案。
    • 代码在 swift 4.0 中有一些 bug。
    • @Rajesh 代替 round(self * divisor) / divisor,在 Swift 4 中做 (self * divisor).rounded() / divisor
    【解决方案3】:

    下面的扩展执行以下操作-

    1. 将数字 10456 显示为 10.5k,将 10006 显示为 10k(不会显示 .0 小数)。
    2. 将为数百万执行上述操作并对其进行格式化,即 10.5M 和 10M
    3. 将以货币格式格式化数千至 9999,即使用逗号,如 9,999

      extension Double {
          var kmFormatted: String {
      
              if self >= 10000, self <= 999999 {
                  return String(format: "%.1fK", locale: Locale.current,self/1000).replacingOccurrences(of: ".0", with: "")
              }
      
              if self > 999999 {
                  return String(format: "%.1fM", locale: Locale.current,self/1000000).replacingOccurrences(of: ".0", with: "")
              }
      
              return String(format: "%.0f", locale: Locale.current,self)
          }
      }
      

    用法:

    let num: Double = 1000001.00 //this should be a Double since the extension is on Double
    let millionStr = num.kmFormatted
    print(millionStr)
    

    打印1M

    它正在行动中-

    【讨论】:

    • 请修正:您的最小千值应该 >= 1000 而不是 10000
    • 不,不应该。此扩展程序将以 9,999 的格式(使用逗号,即货币格式)显示数千到 9999,例如 1000 将是 1,000 ; 2000 将是 2,000。任何等于或大于 10000 或小于或等于 999999 的内容都将以“K”格式显示,依此类推。
    • 啊,我知道你在那里做了什么。有趣的。好吧,对于我的用例,我最终将其更改为 1000。我很抱歉假设您的用例与我的相同。
    • 不用担心,很高兴你知道了。
    • 测试用例:let values = [100, 999, 1000, 1250, 1750, 2000, 2741, 641239, -719409, 247001,999998, 10000000, 100000000, 1e10] 似乎无法处理 1250、1750、2000、2741、1e10 或更大
    【解决方案4】:

    为了补充答案,这里有一个 Swift 4.X 版本,它使用循环在必要时轻松添加/删除单元:

    extension Double {
        var shortStringRepresentation: String {
            if self.isNaN {
                return "NaN"
            }
            if self.isInfinite {
                return "\(self < 0.0 ? "-" : "+")Infinity"
            }
            let units = ["", "k", "M"]
            var interval = self
            var i = 0
            while i < units.count - 1 {
                if abs(interval) < 1000.0 {
                    break
                }
                i += 1
                interval /= 1000.0
            }
            // + 2 to have one digit after the comma, + 1 to not have any.
            // Remove the * and the number of digits argument to display all the digits after the comma.
            return "\(String(format: "%0.*g", Int(log10(abs(interval))) + 2, interval))\(units[i])"
        }
    }
    

    例子:

    $ [1.5, 15, 1000, 1470, 1000000, 1530000, 1791200000].map { $0.shortStringRepresentation }
    [String] = 7 values {
      [0] = "1.5"
      [1] = "15"
      [2] = "1k"
      [3] = "1.5k"
      [4] = "1M"
      [5] = "1.5M"
      [6] = "1791.2M"
    }
    

    【讨论】:

    • 我最喜欢这个答案。添加billiontrillion 并通过我所有的测试用例很容易!
    • 更正:几乎我所有的测试用例。没有让它在负数上工作,抛出Double value cannot be converted to Int because it is either infinite or NaN
    • @lizzy91 确实!我已经更新了代码来解决这个问题,这是因为log10 不能接受否定参数,如果是这种情况,则返回NaN
    • 我知道你已经弄清楚了,但如果其他人偶然发现它并想知道:这是因为实际值存储在 intervalsecond 之一) . Int(log10(abs(interval))) + 2 是显示的位数,不是显示的值
    • 虽然这很好,而且更准确一些;问题是您依赖units 数组以正确的顺序(a)正确(b)。该函数实际上不对数字进行任何检查。所以假设你省略“m”并输入“B”,你喂它 10 亿它不会找到它。因此,units 数组必须是详尽的并且顺序正确
    【解决方案5】:

    答案的一些变化(对于 Int 并正确为百万):

    func formatPoints(num: Int) ->String{
        let thousandNum = num/1000
        let millionNum = num/1000000
        if num >= 1000 && num < 1000000{
            if(thousandNum == thousandNum){
                return("\(thousandNum)k")
            }
            return("\(thousandNum)k")
        }
        if num > 1000000{
            if(millionNum == millionNum){
                return("\(millionNum)M")
            }
            return ("\(millionNum)M")
        }
        else{
            if(num == num){
                return ("\(num)")
            }
            return ("\(num)")
        }
    
    }
    

    【讨论】:

      【解决方案6】:

      对于 swift 4.0.,它的工作完全正常,并根据 @user3483203

      回答

      将Double值转换为字符串的功能

      func formatPoints(num: Double) ->String{
          var thousandNum = num/1000
          var millionNum = num/1000000
          if num >= 1000 && num < 1000000{
              if(floor(thousandNum) == thousandNum){
                  return("\(Int(thousandNum))k")
              }
              return("\(thousandNum.roundToPlaces(places: 1))k")
          }
          if num > 1000000{
              if(floor(millionNum) == millionNum){
                  return("\(Int(thousandNum))k")
              }
              return ("\(millionNum.roundToPlaces(places: 1))M")
          }
          else{
              if(floor(num) == num){
                  return ("\(Int(num))")
              }
              return ("\(num)")
          }
      
      }
      

      制作一个双扩展

      extension Double {
          /// Rounds the double to decimal places value
          mutating func roundToPlaces(places:Int) -> Double {
              let divisor = pow(10.0, Double(places))
              return Darwin.round(self * divisor) / divisor
          }
      }
      

      上述函数的使用

      UILABEL.text = formatPoints(num: Double(310940)!)

      输出:

      【讨论】:

        【解决方案7】:

        Swift 3 中的上述解决方案(来自@qlear):

        func formatPoints(num: Double) -> String {
            var thousandNum = num / 1_000
            var millionNum = num / 1_000_000
            if  num >= 1_000 && num < 1_000_000 {
                if  floor(thousandNum) == thousandNum {
                    return("\(Int(thousandNum))k")
                }
                return("\(thousandNum.roundToPlaces(1))k")
            }
            if  num > 1_000_000 {
                if  floor(millionNum) == millionNum {
                    return "\(Int(thousandNum))k"
                }
                return "\(millionNum.roundToPlaces(1))M"
            }
            else{
                if  floor(num) == num {
                    return "\(Int(num))"
                }
                return "\(num)"
            }
        }
        
        extension Double {
            // Rounds the double to decimal places value
            mutating func roundToPlaces(_ places : Int) -> Double {
                let divisor = pow(10.0, Double(places))
                return (self.rounded() * divisor) / divisor
            }
        }
        

        【讨论】:

          【解决方案8】:

          这是我的方法。

          extension Int {
          func shorted() -> String {
              if self >= 1000 && self < 10000 {
                  return String(format: "%.1fK", Double(self/100)/10).replacingOccurrences(of: ".0", with: "")
              }
          
              if self >= 10000 && self < 1000000 {
                  return "\(self/1000)k"
              }
          
              if self >= 1000000 && self < 10000000 {
                  return String(format: "%.1fM", Double(self/100000)/10).replacingOccurrences(of: ".0", with: "")
              }
          
              if self >= 10000000 {
                  return "\(self/1000000)M"
              }
          
              return String(self)
          }
          

          以下是一些示例:

          print(913.shorted())
          print(1001.shorted())
          print(1699.shorted())
          print(8900.shorted())
          print(10500.shorted())
          print(17500.shorted())
          print(863500.shorted())
          print(1200000.shorted())
          print(3010000.shorted())
          print(11800000.shorted())
          
          913
          1K
          1.6K
          8.9K
          10k
          17k
          863k
          1.2M
          3M
          11M
          

          【讨论】:

            【解决方案9】:

            我已将@AnBisw 的答案转换为使用switch(构建时间友好):

               extension Double {
                var kmFormatted: String {
                    switch self {
                    case ..<1_000:
                        return String(format: "%.0f", locale: Locale.current, self)
                    case 1_000 ..< 999_999:
                        return String(format: "%.1fK", locale: Locale.current, self / 1_000).replacingOccurrences(of: ".0", with: "")
                    default:
                        return String(format: "%.1fM", locale: Locale.current, self / 1_000_000).replacingOccurrences(of: ".0", with: "")
                    }
                }
            }
            

            【讨论】:

              【解决方案10】:

              基于@qlear 的解决方案。
              我注意到如果数字正好是 1000000,它将返回 1000000 未格式化。
              所以我把它添加到函数中。我还包括了负值。因为不是每个人都在赚钱!

              func formatPoints(num: Double) ->String{
                  let thousandNum = num/1000
                  let millionNum = num/1000000
                  if num > 0
                  {
                      if num >= 1000 && num < 1000000{
                          if(floor(thousandNum) == thousandNum){
                              return("\(Int(thousandNum))k")
                          }
                          return("\(round1(thousandNum, toNearest: 0.01))k")
                      }
                      if num > 1000000{
                          if(floor(millionNum) == millionNum){
                              return("\(Int(thousandNum))k")
                          }
                          return ("\(round1(millionNum, toNearest: 0.01))M")
                      }
                      else if num == 1000000
                      {
                          return ("\(round1(millionNum, toNearest: 0.01))M")
                      }
                      else{
                          if(floor(num) == num){
                              return ("\(Int(num))")
                          }
                          return ("\(round1(num, toNearest: 0.01))")
                      }
                  }
                  else
                  {
              
                      if num <= -1000 && num > -1000000{
                          if(floor(thousandNum) == thousandNum){
                              return("\(Int(thousandNum))k")
                          }
                          return("\(round1(thousandNum, toNearest: 0.01))k")
                      }
                      if num < -1000000{
                          if(floor(millionNum) == millionNum){
                              return("\(Int(thousandNum))k")
                          }
                          return ("\(round1(millionNum, toNearest: 0.01))M")
                      }
                      else if num == -1000000
                      {
                          return ("\(round1(millionNum, toNearest: 0.01))M")
                      }
                      else{
                          if(floor(num) == num){
                              return ("\(Int(num))")
                          }
                          return ("\(round1(num, toNearest: 0.01))")
                      }
                  }
              
              }
              

              当然还有号码扩展:

              extension Double {
                  /// Rounds the double to decimal places value
                  func round1(_ value: Double, toNearest: Double) -> Double {
                      return Darwin.round(value / toNearest) * toNearest
                  }
              
              }
              

              【讨论】:

                【解决方案11】:

                此解决方案使用ByteCountFormatter,但用于任何数字类型的任何大数字缩写。为什么这个由 Apple 为字节编写的格式化程序仍然未知。

                extension Numeric {
                    
                    var abbreviated: String {
                        let bytesString = ByteCountFormatter.string(fromByteCount: (self as! NSNumber).int64Value, countStyle: .decimal)
                        let numericString = bytesString
                            .replacingOccurrences(of: "bytes", with: "")
                            .replacingOccurrences(of: "B", with: "") // removes B (bytes) in 'KB'/'MB'/'GB'
                            .replacingOccurrences(of: "G", with: "B") // replace G (Giga) to just B (billions)
                        return numericString.replacingOccurrences(of: " ", with: "")
                    }
                }
                

                【讨论】:

                  【解决方案12】:

                  @chrisz 答案的小幅改进,Swift-4 Doble extension - 在所有情况下都可以正常工作。

                  extension Double {
                  
                    // Formatting double value to k and M
                    // 1000 = 1k
                    // 1100 = 1.1k
                    // 15000 = 15k
                    // 115000 = 115k
                    // 1000000 = 1m
                    func formatPoints() -> String{
                          let thousandNum = self/1000
                          let millionNum = self/1000000
                          if self >= 1000 && self < 1000000{
                              if(floor(thousandNum) == thousandNum){
                                  return ("\(Int(thousandNum))k").replacingOccurrences(of: ".0", with: "")
                              }
                              return("\(thousandNum.roundTo(places: 1))k").replacingOccurrences(of: ".0", with: "")
                          }
                          if self > 1000000{
                              if(floor(millionNum) == millionNum){
                                  return("\(Int(thousandNum))k").replacingOccurrences(of: ".0", with: "")
                              }
                              return ("\(millionNum.roundTo(places: 1))M").replacingOccurrences(of: ".0", with: "")
                          }
                          else{
                              if(floor(self) == self){
                                  return ("\(Int(self))")
                              }
                              return ("\(self)")
                          }
                      }
                  
                      /// Returns rounded value for passed places
                      ///
                      /// - parameter places: Pass number of digit for rounded value off after decimal
                      ///
                      /// - returns: Returns rounded value with passed places
                      func roundTo(places:Int) -> Double {
                          let divisor = pow(10.0, Double(places))
                          return (self * divisor).rounded() / divisor
                      }
                  }
                  




                  【讨论】:

                  • @Janky 我认为您犯了一些错误,您可以在此处查看我的答案中的结果。我已经从我身边正确地测试了它并且运行良好。如果您有任何遗漏的情况,您可以在此处讨论,而不是直接对答案投反对票。
                  • Dude @Janky 您的数据或逻辑有问题。这个答案有效,我发布的答案也有效。
                  【解决方案13】:

                  如果你想在 lacs 中:

                   extension Int {
                  func shorted() -> String {
                      if self >= 1000 && self < 10000 {
                          return String(format: "%.1fK", Double(self/100)/10).replacingOccurrences(of: ".0", with: "")
                      }
                  
                      if self >= 10000 && self < 100000 {
                          return "\(self/1000)k"
                      }
                  
                      if self >= 100000 && self < 1000000 {
                          return String(format: "%.1fL", Double(self/10000)/10).replacingOccurrences(of: ".0", with: "")
                      }
                  
                      if self >= 1000000 && self < 10000000 {
                          return String(format: "%.1fM", Double(self/100000)/10).replacingOccurrences(of: ".0", with: "")
                      }
                  
                      if self >= 10000000 {
                          return "\(self/1000000)M"
                      }
                  
                      return String(self)
                  }
                  }
                  

                  【讨论】:

                    【解决方案14】:

                    因为我们都或多或少不同意

                    func FormatFriendly(num: Double) ->String {
                        var thousandNum = num/1000
                        var millionNum = num/1000000
                    
                        if num >= 1000 && num < 1000000{
                            if(floor(thousandNum) == thousandNum){
                                return("\(Int(thousandNum))K").replacingOccurrences(of: ".0", with: "")
                            }
                            return("\(thousandNum.roundToPlaces(places: 1))K").replacingOccurrences(of: ".0", with: "")
                        }
                    
                        if num >= 1000000{
                            //if(floor(millionNum) == millionNum){
                                //return("\(Int(thousandNum))K").replacingOccurrences(of: ".0", with: "")
                            //}
                        return ("\(millionNum.roundToPlaces(places: 1))M").replacingOccurrences(of: ".0", with: "")
                        }else {
                            if(floor(num) == num){
                                return ("\(Int(num))")
                            }
                            return ("\(num)")
                        }
                    }
                    
                    extension Double {
                        /// Rounds the double to decimal places value
                        mutating func roundToPlaces(places: Int) -> Double {
                            let divisor = pow(10.0, Double(places))
                            return Darwin.round(self * divisor) / divisor
                        }
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2013-02-03
                      • 2017-12-20
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-10-12
                      • 1970-01-01
                      • 2017-08-09
                      相关资源
                      最近更新 更多