This is a coding challenge inspired bt @starmaq’s Coding Challenge
The reason it’s here it’s because
Here’s the reqiurement:
- Has to work on Roblox Studio so it has to be written in Lua 5.1 and you can’t use features vanilla Lua has but Roblox Lua disabled
- No HttpService
You are given a data to create a function that formats and abbreviates the number using that data. The data is a table
{
decimalSymbol = ',',
groupSymbol = ' ',
negativeSymbol = '-',
groupSize = { 3 },
minimumGroupingDigits = 2,
compact = { '0', '0', '0', '0', '0', '0', '0 M', '00 M', '000 M', '0 B', '00 B', '000 B', '0 T', '00 T', '000 T' }
}
key | Meaning |
---|---|
decimalSymbol | The decimal symbol |
groupSymbol | The digit grouping symbol |
negativeSymbol | The negative sign symbol on negative numbers |
groupSize | The size of grouping, { 3 } means group every digit { 3, 2 } means group the last 3 then every 2 digits (e.g. 12,34,56,789). |
minimumGroupingDigits:
A value that controls what number can be grouped, it cannot be 0
, it’s this is infinity, don’t group the number at all.
minimumGroupingDigits | index 1 of grouping size | value | output |
---|---|---|---|
1 | 3 | 1000 | 1,000 |
2 | 3 | 1000 | 1000 |
1 | 3 | 10000 | 10,000 |
2 | 3 | 10000 | 10,000 |
3 | 3 | 10000 | 10000 |
3 | 3 | 100000 | 100,000 |
1 | 4 | 10000 | 1,0000 |
1 | 4 | 100000 | 10,0000 |
2 | 4 | 10000 | 10000 |
2 | 4 | 100000 | 10,0000 |
inf | 3 | 1234567890 | 1234567890 |
compact:
The table of abbreviated string
- The minimumGroupingDigits is always 2 if the minimumGroupingDigit normally is 1 if you’re abbreviating numbers, no exceptions
- Just
0
means don’t abbreviate the number - The amount of
0
is the size of the group (e.g.12345
on00K
will be12K
) - Ignore the single quote, e.g.
12345
on00K'.'
will be12K.
, but''
will be'
- Group the abbreviated number too e.g. (
12,345T
instead of12345T
) - The decimal size must be zero if the size is bigger than 1 (e.g.
12K
instead of12.3K
), and the decimal size must be one if the size is 1 and it’s not zero (e.g.1.2K
instead of1K
but1K
instead of1.0K
)
There are no holding hands, I can only help if you don’t get it or the rules.
Boilerplate:
local data =
{
{
decimalSymbol = ',',
groupSymbol = ' ',
negativeSymbol = '-',
groupSize = { 3 },
minimumGroupingDigits = 2,
compact = { '0', '0', '0', '0', '0', '0', '0 M', '00 M', '000 M', '0 B', '00 B', '000 B', '0 T', '00 T', '000 T' }
},
{
decimalSymbol = ' decimal ',
groupSymbol = ' group ',
negativeSymbol = '-',
groupSize = { 3, 2 },
minimumGroupingDigits = 1,
compact = { '0', '0', '0', '0', 'TestA 0', 'TestA 00', 'TestB 000', '0 TestC', 'TestC 00 ttest', '000 TestC' }
},
{
decimalSymbol = '.',
groupSymbol = ',',
negativeSymbol = '-',
groupSize = { 3 },
minimumGroupingDigits = 1,
compact = { '0', '0', '0', '0', '0万', '00万', '000万', '0000万', '0億', '00億', '000億', '0000億', '0兆', '00兆', '000兆' }
},
{
decimalSymbol = ',',
groupSymbol = '.',
negativeSymbol = '-',
groupSize = { 3 },
minimumGroupingDigits = 1,
compact = { '0', '0', '0', '0', '0', '0', '0 Mio.', '0 Mio.', '0 Mio.', '0 Mrd.', '00 Mrd.', '000 Mrd.', '0 Bio.', '00 Bio.', '000 Bio.' }
},
{
decimalSymbol = ',',
groupSymbol = '.',
negativeSymbol = '-',
groupSize = { 3 },
minimumGroupingDigits = 2,
compact = { '0', '0', '0', '0', '0', '0', '0 M', '00 M', '000 M', '0000 M', '00 MRD', '000 MRD', '0 B', '00 B', '000 B' }
},
{
decimalSymbol = '.',
groupSymbol = ',',
negativeSymbol = '-',
groupSize = { 3 },
minimumGroupingDigits = 1,
compact = { '0', '0', '0', '0K', '00K', '000K', '0M', '00M', '000M', '0B', '00B', '000B', '0T', '00T', '000T' };
}
}
local examples = { 1500, 23456, 5343442, 865849384, 12345000000000000 }
function FormatNumber(value, data)
-- Your code here
end;
function AbbreviateNumber(value, data)
-- Your code here
end;
for _, d in ipairs(data) do
for _, v in ipairs(examples) do
print(FormatNumber(v, d))
print(AbbreviateNumber(v, d))
end
end
Expected output
Data 1:
1500
1500
23 456
23 456
5 343 442
5,3 M
865 849 384
865 M
12 345 000 000 000 000
12 345 T
Data 2:
1 group 500
1500
23 group 456
TestA 2 decimal 3
53 group 43 group 442
TestB 534
86 group 58 group 49 group 384
TestC 86 ttest
12 group 34 group 50 group 00 group 00 group 00 group 00 group 000
12 group 34 group 50 group 00 group 000 TestC
Data 3:
1,500
1500
23,456
2.3万
5,343,442
543万
865,849,384
8.6億
12,345,000,000,000,000
12,345兆
Data 4:
1.500
1500
23.456
23.456
5.343.442
5,3 Mio.
865.849.384
865 Mio.
12.345.000.000.000.000
12.345 Bio.
Data 5:
1500
1500
23.456
23.456
5.343.442
5,3 M
865.849.384
865 M
12.345.000.000.000.000
12.345 B
Data 6:
1,500
1.5K
23K
23K
5,343,442
5.3M
865,849,384
865M
12,345,000,000,000,000
12,345T
Good luck!
Answer, don't spoil yourself
1> Do the formatting number first. Convert number to string first, use :format
instead of tostring
, as because tostring will also include expoentents, which we don’t want here.
2> Create the parts, negative, integer, decimal, fraction
3> Format the integer
4> The return the value, replace -
with the negative symbol and .
(doesn’t matter literal dot or not because .
means any charcter, and the decimal can only be `` or .
) to a decimal symbol to ensure it’s actually there, and not empty
5> Create minimumGroupingDigit override, just in case
function FormatNumber(value, data, mgd_override)
if type(value) == "number" then
value = ("%.0f"):format(value);
end;
local neg, int, dec, frac = value:match("(-?)(%d*)([.]?)(%d*)");
if #int >= data.groupSize[1] + (mgd_override or data.minimumGroupingDigits) then
-- This is the grouping part
local ret = '';
local i = 1;
while #int > data.groupSize[i] do
ret = data.groupSymbol .. value:sub(-data.groupSize[i]) .. ret;
int = int:sub(1, -(data.groupSize[i] + 1));
if i < #data.groupSize then
i = i + 1
end;
end;
int = int .. ret;
end;
return neg:gsub('-', data.negativeSymbol) .. int .. dec:gsub('.', data.decimalSymbol) .. frac;
end;
5> Once your done, abbreviate the number, check if the value is 0 because the minimumGroupingDigits must be ≥2, use math.max to get the highest value
6> FormatNumber with minimumGroupingDigit overrided to ≥2
7> Use string.sub/divide numbers to get parts of the number.
8> Use string:gsub() to find how many zeros are there, do note that subtract length of value to length of the data.compact size with max at 0 just in case there are more
9> Add a full stop (decimal separator) with the next part of the number if the size is 1
function AbbreviateNumber(value, data)
if type(value) == "number" then
value = ("%.0f"):format(value);
end;
local cformat = data.compact[math.min(#value, #data.compact)];
if cformat == '0' or cformat == '' then
return FormatNumber(value, data, math.max(data.minimumGroupingDigits, 2));
else
local _, csize = cformat:gsub('0', '');
csize = csize + math.max(#value - #data.compact, 0);
local dsize = csize == 1 and 1 or 0;
return (cformat:gsub(
'0+',
FormatNumber(value:sub(1, csize) .. (dsize == 0 and '' or '.' .. value:sub(csize + 1, csize + dsize)), data, math.max(data.minimumGroupingDigits, 2))
):gsub("'([^']+)'", "%1"));
end;
end;