Any ideas how I can improve this? ex: 1,000 > 1k

Theres insane mess about this code, and I cannot comprehend it anymore. Explanation are really appreciated. (Some code taken from Zednov’s Tycoon Kit)

local module = {}

local ShortTable = {
	k = 3 * 1,
	m = 3 * 2,
	b = 3 * 3,
	t = 3 * 4,
	q = 3 * 5,
	qn = 3 * 6,
	sx = 3 * 7,
	sp = 3 * 8,
	oc = 3 * 9,
	no = 3 * 10,
	de = 3 * 11,
	ude = 3 * 12,
	dde = 3 * 13,
	tde = 3 * 14,
	qde = 3 * 15,
	qnde = 3 * 16,
	sxde = 3 * 17,
	spde = 3 * 18,
	ocde = 3 * 19,
	node = 3 * 20,
	v = 3 * 21
}

function module:ConvertShort(Filter_Num)
	local x = tostring(Filter_Num)
	if #x >= ShortTable[8] + 1 then
		local important = (#x - 24)
		return x:sub(0,(important)).."."..(x:sub(#x - 17,(#x - 17))).."sp+"
	elseif #x >= ShortTable[7] + 1 then
		local important = (#x - 21)
		return x:sub(0,(important)).."."..(x:sub(#x - 15,(#x - 15))).."sx+"
	elseif #x >= ShortTable[6] + 1 then
		local important = (#x - 18)
		return x:sub(0,(important)).."."..(x:sub(#x - 13,(#x - 13))).."qn+"
	elseif #x >= ShortTable[5] + 1 then
		local important = (#x - 15)
		return x:sub(0,(important)).."."..(x:sub(#x - 11,(#x - 11))).."q+"
	elseif #x >= ShortTable[4] + 1 then
		local important = (#x - 12)
		return x:sub(0,(important)).."."..(x:sub(#x - 9,(#x - 9))).."t+"
	elseif #x >= ShortTable[3] + 1 then
		local important = (#x - 9)
		return x:sub(0,(important)).."."..(x:sub(#x - 7,(#x - 7))).."b+"
	elseif #x >= ShortTable[2] + 1 then
		local important = (#x - 6)
		return x:sub(0,(important)).."."..(x:sub(#x - 5,(#x - 5))).."m+"
	elseif #x >= ShortTable[1] + 1 then
		return x:sub(0,(#x - 3)).."."..(x:sub(#x - 2,(#x - 2))).."k+"
	else
		return Filter_Num
	end
end

return module

function abbreviateNumber (n)
	-- Abhi's Number Abbreviation System V 2.3
	local s = tostring(math.floor(n))
	return string.sub(s, 1, ((#s - 1) % 3) + 1) .. ({"", "K", "M", "B", "T", "QA", "QI", "SX", "SP", "OC", "NO", "DC", "UD", "DD", "TD", "QAD", "QID", "SXD", "SPD", "OCD", "NOD", "VG", "UVG"})[math.floor((#s - 1) / 3) + 1]
end

1 Like

Best part of this is that you can continue to add as many as you want simply by adding another:

,”AbbreviationHere”

To it

Upon running the function, it says: attempt to call missing method ‘ConvertShort’ of table
note: this is ran in console

local hey = require(game:GetService('ServerScriptService').Abbreviate):shorten(1) print(hey)

You’re not calling it right…? It’s a simple function, not a module or anything like that

This is a Simple way to Abbriviate Numbers:

AbNum = {
K = 10^3;
M = 10^6;
B = 10^9;
}


function AbbNumber(x: number?)
local num
local ff = 0

for s, value in pairs(AbNum) do -- s = string (Name) : value = number
    if x >= value and x > ff then
       str = math.floor(x/value)..s -- Divides and concats
    end
end
return str -- returns
end

AbbNumber(1000) -- should print "1K" unless i made a mistake

i mean like i put it in my module so that i can call anywhere i want

Okay then you would do this:

local module = {} 

function module:AbbreviateNumber(n) 
        local s = tostring(math.floor(n))
	return string.sub(s, 1, ((#s - 1) % 3) + 1) .. ({"", "K", "M", "B", "T", "QA", "QI", "SX", "SP", "OC", "NO", "DC", "UD", "DD", "TD", "QAD", "QID", "SXD", "SPD", "OCD", "NOD", "VG", "UVG"})[math.floor((#s - 1) / 3) + 1]
end 

return module 

Ok thanks, ill bookmark this post so i wont forget this

1 Like

Then you can just call this module with require run that function with the number in it

This is nice and compact, but only works for numbers up to around 9.2 * 1e18. After that it just gives “M” as the suffix. Here’s a version that works up to ~10e59 or higher

--[[
Each value is the prefix corresponding to a power of 10 given by the key.
]]
local METRIC_PREFIXES = {
    [3 * 0] = "",
    [3 * 1] = "k",
    [3 * 2] = "m",
    [3 * 3] = "b",
    [3 * 4] = "t",
    [3 * 5] = "q",
    [3 * 6] = "qn",
    [3 * 7] = "sx",
    [3 * 8] = "sp",
    [3 * 9] = "oc",
    [3 * 10] = "no",
    [3 * 11] = "de",
    [3 * 12] = "ude",
    [3 * 13] = "dde",
    [3 * 14] = "tde",
    [3 * 15] = "qde",
    [3 * 16] = "qnde",
    [3 * 17] = "sxde",
    [3 * 18] = "spde",
    [3 * 19] = "ocde",
    [3 * 20] = "node",
    [3 * 21] = "v",
}

--[[
Given a table t and a numeric index i, find the greatest populated index of t less than or equal to i.
t should be a dictionary from numbers to non-nil values.
]]
function greatest_index_lte(t, i)
    assert(i >= 0, ("Cannot reliably search for indices less than 0 (got %g)!"):format(i))
    for j = math.floor(i), 0, -1 do
        if t[j] ~= nil then 
            return j
        end
    end
    error(("No indices under %g found!"):format(math.floor(index)))
end

function format_metric_suffix(n, number_format)
    local n_log10 = math.log10(n)
    local prefix_index = greatest_index_lte(METRIC_PREFIXES, math.floor(n_log10))
    local prefix = METRIC_PREFIXES[prefix_index]
    local n_remainder = n / math.pow(10, prefix_index)

    number_format = (number_format or "%g") .. "%s"
    return number_format:format(n_remainder, prefix)
end

print(format_metric_suffix(10e59))

It can also easily be partly memoized for a 2x speed improvement:

--[[
Each value is the prefix corresponding to a given power of 10.
]]
local METRIC_PREFIXES =
    [3 * 0] = "",
	[3 * 1] = "k",
	[3 * 2] = "m",
	[3 * 3] = "b",
	[3 * 4] = "t",
	[3 * 5] = "q",
	[3 * 6] = "qn",
	[3 * 7] = "sx",
	[3 * 8] = "sp",
	[3 * 9] = "oc",
	[3 * 10] = "no",
	[3 * 11] = "de",
	[3 * 12] = "ude",
	[3 * 13] = "dde",
	[3 * 14] = "tde",
	[3 * 15] = "qde",
	[3 * 16] = "qnde",
	[3 * 17] = "sxde",
	[3 * 18] = "spde",
	[3 * 19] = "ocde",
	[3 * 20] = "node",
	[3 * 21] = "v",
}

--[[
Curries the first parameter of a function.
]]
function curried(f, value)
	return function(...)
		return f(value, ...)
	end
end

--[[
Memoizes a (pure) function of 1 parameter.
]]
function memoized(f)
	local known_inputs = {}
	return function(input)
		local known_value = known_inputs[input]
		if known_value then
			--print("Known value")
			return known_value
		else
			local value = f(input)
			--print("New value", value)
			known_inputs[input] = value
			return value
		end
	end
end

--[[
Given a table t and a numeric index i, find the greatest populated index of t less than or equal to i.
t should be a dictionary from numbers to non-nil values.
]]
function greatest_index_lte(t, i)
	assert(i >= 0, ("Cannot reliably search for indices less than 0 (got %g)!"):format(i))
	for j = math.floor(i), 0, -1 do
		if t[j] ~= nil then 
			return j
		end
	end
	error(("No indices under %g found!"):format(math.floor(index)))
end

local memoized_greatest_index_lte = memoized(curried(greatest_index_lte, METRIC_PREFIXES))

function format_metric_suffix(n, number_format)
	local n_log10 = math.log10(n)
	local prefix_index = memoized_greatest_index_lte(math.floor(n_log10))
	local prefix = METRIC_PREFIXES[prefix_index]
	local n_remainder = n / math.pow(10, prefix_index)

	number_format = (number_format or "%g") .. "%s"
	return number_format:format(n_remainder, prefix)
end

this is slightly simpler to look at than a skyscraper of ifs, but really time consuming to put in the numbers at metric prefixes

1 Like

sorry if i didn’t respond to you, but putting the numbers up is time consuming and some of the values you put in doesnt get used

Whoops, mine is buggy at less than 1k. I edited my previous comment.

is there anyway on how i can make a decimal like:

number is: 4220000

i want to show it as: 4.2M but i don’t wanna show the second two

how to do this? im unfamiliar with this abbreviation method

And then you call it by doing this?

format_metric_suffix(10e59)

but what value would be inserted for number_format ?

None is necessary as it uses a default format string of “%g” which just formats the number part using a decent default format, but you might want to replace it with a format string for e.g. 3 decimal places

This is one way to get the decimal version you want of the number:

local numberHere = 795824 
print(string.format("%.1f",numberHere/10^(math.ceil(math.log10(numberHere))-1))) 

Then you can just add whatever letter after it that you need depending on the amount of digits that are in the number (specifically made for scientific notation but could potentially be altered for other things by multiplying the number by 10 for the divisibility the number of digits in the number has with the module 3

DigitsInNumber = math.ceil(math.log10(numberHere))

What do you think of this code I made?

function Abbreviate(numberHere,Notation) -- Notation: 1 = Scientific, 2 = Letters, Default = 2 
	local DigitsInNumber = math.max(math.ceil(math.log10(numberHere+1)),1) 
	
	local FormattedNumber 
	local NotationToUse 
	if Notation == 1 then -- Scientific Notation 
		FormattedNumber = string.sub(tostring(numberHere/10^(DigitsInNumber-1)),1,3) 
		NotationToUse = FormattedNumber.."e"..DigitsInNumber-1 
	elseif (Notation and Notation == 2) or not Notation then -- Letters 
		local TableOfLetters = { 
			"", 
			"K", 
			"M", 
			"B", 
			"T", 
			"QA", 
			"QI", 
			"SX", 
			"SP", 
			"OC", 
			"NO", 
			"DC", 
			"UD", 
			"DD" 
		} 
		local NumberToShow = 1.5*(DigitsInNumber%3)^2 - 3.5*(DigitsInNumber%3) + 5 
		FormattedNumber = string.sub(tostring(numberHere/10^(DigitsInNumber-1)),1,NumberToShow) 
		NotationToUse = string.sub(FormattedNumber*(10^((DigitsInNumber-1)%3)),1,NumberToShow)..TableOfLetters[math.ceil(DigitsInNumber/3)] 
	end 
	return NotationToUse 
end