具有可变数量的有效数字的格式编号取决于大小

时间:2014-08-16 02:17:18

标签: language-agnostic lua formatting format

我有一个小功能,显示某个数字值的格式化数量。目的是根据数字的大小显示“常识”数量的重要数字。因此,例如,1,234为1.2k,12,345为12k,123,456为123k。

换句话说,我希望在给定数量级的下端显示单个小数,但不是对于较大的值,它只是无用的噪声。

我需要这个功能一直扩展到1到几十亿。目前的解决方案就是分支它:

-- given `current`
local text = (
  current > 9,999,999,999 and ('%dB')  :format(current/1,000,000,000) or
  current >   999,999,999 and ('%.1fB'):format(current/1,000,000,000) or
  current >     9,999,999 and ('%dM')  :format(current/1,000,000) or
  current >       999,999 and ('%.1fM'):format(current/1,000,000) or
  current >         9,999 and ('%dk')  :format(current/1,000) or
  current >           999 and ('%.1fk'):format(current/1,000) or
  ('%d'):format(current)  -- show values < 1000 floored
)
textobject:SetText(text)

-- code formatted for readability

我觉得非常难看。是否有一些优雅的公式以这种方式舍入数字而不仅仅为我需要支持的1000个因素添加另外的(两个)子句?

2 个答案:

答案 0 :(得分:1)

直到朋友给我一个解决方案(根据长度检查数字的大小),我才意识到这实际上是多么简单。我将其转换为使用日志来查找幅度,现在有一个优雅的工作答案:

local suf = {'k','M','B','T'}
local function clean_format(val)
  if val == 0 then return '0' end  -- *Edit*: Fix an error caused by attempting to get log10(0)
  local m = math.min(#suf,math.floor(math.log10(val)/3))  -- find the magnitude, or use the max magnitude we 'understand'
  local n = val / 1000 ^ m                                -- calculate the displayed value
  local fmt = (m == 0 or n >= 10) and '%d%s' or '%.1f%s'  -- and choose whether to apply a decimal place based on its size and magnitude
  return fmt:format(n,suf[m] or '')
end

将其扩展为支持更大的1000因子就像将下一个条目放在suf数组中一样简单。

注意:出于与语言无关的目的,Lua数组是基于1的,而不是基于零的。上述解决方案会在许多其他语言中出现一个一个错误。

答案 1 :(得分:0)

将范围及其后缀放在表格中。

local multipliers = {
  {10^10, 'B', 10^9},
  {10^9, 'B', 10^9, true},
  {10^7, 'M', 10^6},
  {10^6, 'M', 10^6, true},
  {10^4, 'k', 10^3},
  {10^3, 'k', 10^3, true},
  {1, '', 1},
}

备用变量第4位的可选true值适用于%.1f占位符。第三个指标是除数。

现在,迭代此表(使用ipairs)并相应地格式化:

function MyFormatter( current )
    for i, t in ipairs( multipliers ) do
      if current >= t[1] then
        local sHold = (t[4] and "%.1f" or "%d")..t[2]
        return sHold:format( current/t[3] )
      end
    end
end