如何根据价格添加自定义舍入规则
How do I add custom rounding rules depending on the price
我可能只见树木不见森林,但我在根据自定义规则集对价格的整数和小数进行舍入时遇到问题。
示例:
100-200 之间的所有价格(以美元为单位)应四舍五入为 50 或 90 美分。此外,该点左侧的数字应增加到最接近的数字除以 5.
- 101.10 ~ 105.50
- 126.40 ~ 130.50
- 144.60 ~ 145.90
- 156.60 ~ 160.90
下面是我设置的数据结构,我想我可能会用它来计算舍入。
const data = {
"us": [
{
"start": 100,
"end": 200,
"integer": 5,
"decimals": [
{"start": 0, "end": 50, "value": 50},
{"start": 50, "end": 90, "value": 90},
]
}
]
};
// I have made price a string so I can do split(), is there a better way?
const price = '101.10';
let priceParts = price.split('.');
for (const item of data.us) {
if (priceParts[0] >= item.start && priceParts[0] <= item.end) {
// Round up priceParts[0] with item.integer
// Obviously below is incorrect, but I was hoping you guys have a neat function for it
priceParts[0] = Number(priceParts[0]) + item.integer
for (const decimal of item.decimals) {
if (priceParts[1] <= decimal.start && priceParts[1] >= decimal.end) {
// Round up priceParts[1] with decimal.value
priceParts[1] = decimal.value;
}
}
}
}
const newPrice = Number(priceParts.join('.')).toFixed(2);
// newPrice = 106.90
console.log(newPrice);
- 你会怎么解决?
- 我走的路对吗?
- 是否已经有库可以执行此操作(我在 Google 上找到的库似乎不太合适)?
整数部分为parseInt(price)
,小数部分为价格减去整数部分。然后对于小数部分,你只需要找到与边界匹配的第一组,并使用这些值来调整它。
类似
const data = {
"us": [{
"start": 100,
"end": 200,
"integer": 5,
"decimals": [{
"start": 0,
"end": 50,
"value": 50
},
{
"start": 50,
"end": 90,
"value": 90
},
]
}]
};
const price = 101.10;
let integerPart = parseInt(price);
let decimalPart = (price - integerPart) * 100;
for (const item of data.us) {
if (integerPart > item.start && integerPart <= item.end) {
const needsAdjustment = integerPart % item.integer > 0;
if (needsAdjustment) {
integerPart = (parseInt(integerPart / item.integer) + 1) * item.integer
}
const decimalLimitGroup = item.decimals.find(decimalLimit => decimalPart >= decimalLimit.start && decimalPart <= decimalLimit.end);
if (decimalLimitGroup) {
decimalPart = decimalLimitGroup.value
}
}
}
const newPrice = (integerPart + (decimalPart / 100)).toFixed(2);
// newPrice = 106.90
console.log(newPrice);
你用下面的行“四舍五入”到以下 item.integer
。
priceParts[0] = Number(priceParts[0]) + item.integer
唯一缺少的是整数除以 item.integer
时的余数。
const integer = Number(priceParts[0]);
const remainder = integer % item.integer;
priceParts[0] = integer + item.integer - remainder;
我们来看一个例子:
// say number = 12 and you want to round up to multiples of 5
const remainder = 12 % 5; // 2
const result = 12 + 5 - 2; // 15
上述解决方案存在两个问题。如果余数是 0
,它出现在 0、5、10、15 等处,您不想将 5
添加到数字中。否则 10
将四舍五入为 15
而 15
将四舍五入为 20
.
因此,如果余数是 0
(假),我们只使用数字,因为它已经可以被 item.integer
整除。意思是上面变成了:
const integer = Number(priceParts[0]);
const remainder = integer % item.integer;
if (remainder) {
priceParts[0] = integer + item.integer - remainder;
} else {
priceParts[0] = integer;
}
另一个问题是上面假设输入数字是正数。如果可以提供负数,则必须更改:
const remainder = integer % item.integer;
进入:
const modulo = ((integer % item.integer) + item.integer) % item.integer;
这是因为 -12
确实有 -2
的余数,所以如果您遵循相同的原则,您将得到 -12 + 5 - -2 = -5
。对于负数,我们需要取模。 -12
的模是 3
导致 -12 + 5 - 3 = -10
.
详情请参阅 remainder operator 的描述。
一个更简单的解决方案是使用 Math.floor()
、Math.round()
或 Math.ceil()
中的内置程序为您进行四舍五入。因为它四舍五入到最接近的整数,所以我们必须将整数转换为“5 的倍数”数字,对其进行四舍五入,最后将其转换回普通整数。
priceParts[0] = Math.ceil(Number(priceParts[0]) / item.integer) * item.integer;
这里的好处是 item.integer
(此处为 5)的倍数或负数没有奇怪的舍入情况。
随着整数四舍五入的方式,我个人会使用不同的方法。您可以完全使用数字值而不是专注于小数的字符串表示。
您可以使用 Math.floor(number)
获取数字的整数部分,您可以使用 (number - integer) * 100
获取小数部分。如果将小数点除以 100,则可以将小数点加到整数上,而不是将它们连接在一起。
下面的代码片段使用 find()
搜索规则数组以找到符合条件的规则。
function createRound(rules) {
return function round(num) {
const int = Math.floor(num);
const dec = (num - int) * 100;
const rule = rules.find(({start, end}) => num >= start && num <= end);
if (!rule) return num; // or throw error
const decRule = rule.decimals
.find(({start, end}) => dec >= start && dec <= end)
|| { value: dec }; // or throw error
return Math.ceil(int / rule.integer) * rule.integer
+ decRule.value / 100;
};
}
const data = {
"us": [
{
"start": 100,
"end": 200,
"integer": 5,
"decimals": [
{"start": 0, "end": 50, "value": 50},
{"start": 50, "end": 90, "value": 90},
]
}
]
};
const round = createRound(data.us);
console.log(round(101.10)); // 105.50
console.log(round(126.40)); // 130.50
console.log(round(144.60)); // 145.90
console.log(round(156.60)); // 160.90
console.log(round( 12.34)); // 12.34 (no rule)
console.log(round(156.95)); // 160.95 (no decimal rule)
我可能只见树木不见森林,但我在根据自定义规则集对价格的整数和小数进行舍入时遇到问题。
示例:
100-200 之间的所有价格(以美元为单位)应四舍五入为 50 或 90 美分。此外,该点左侧的数字应增加到最接近的数字除以 5.
- 101.10 ~ 105.50
- 126.40 ~ 130.50
- 144.60 ~ 145.90
- 156.60 ~ 160.90
下面是我设置的数据结构,我想我可能会用它来计算舍入。
const data = {
"us": [
{
"start": 100,
"end": 200,
"integer": 5,
"decimals": [
{"start": 0, "end": 50, "value": 50},
{"start": 50, "end": 90, "value": 90},
]
}
]
};
// I have made price a string so I can do split(), is there a better way?
const price = '101.10';
let priceParts = price.split('.');
for (const item of data.us) {
if (priceParts[0] >= item.start && priceParts[0] <= item.end) {
// Round up priceParts[0] with item.integer
// Obviously below is incorrect, but I was hoping you guys have a neat function for it
priceParts[0] = Number(priceParts[0]) + item.integer
for (const decimal of item.decimals) {
if (priceParts[1] <= decimal.start && priceParts[1] >= decimal.end) {
// Round up priceParts[1] with decimal.value
priceParts[1] = decimal.value;
}
}
}
}
const newPrice = Number(priceParts.join('.')).toFixed(2);
// newPrice = 106.90
console.log(newPrice);
- 你会怎么解决?
- 我走的路对吗?
- 是否已经有库可以执行此操作(我在 Google 上找到的库似乎不太合适)?
整数部分为parseInt(price)
,小数部分为价格减去整数部分。然后对于小数部分,你只需要找到与边界匹配的第一组,并使用这些值来调整它。
类似
const data = {
"us": [{
"start": 100,
"end": 200,
"integer": 5,
"decimals": [{
"start": 0,
"end": 50,
"value": 50
},
{
"start": 50,
"end": 90,
"value": 90
},
]
}]
};
const price = 101.10;
let integerPart = parseInt(price);
let decimalPart = (price - integerPart) * 100;
for (const item of data.us) {
if (integerPart > item.start && integerPart <= item.end) {
const needsAdjustment = integerPart % item.integer > 0;
if (needsAdjustment) {
integerPart = (parseInt(integerPart / item.integer) + 1) * item.integer
}
const decimalLimitGroup = item.decimals.find(decimalLimit => decimalPart >= decimalLimit.start && decimalPart <= decimalLimit.end);
if (decimalLimitGroup) {
decimalPart = decimalLimitGroup.value
}
}
}
const newPrice = (integerPart + (decimalPart / 100)).toFixed(2);
// newPrice = 106.90
console.log(newPrice);
你用下面的行“四舍五入”到以下 item.integer
。
priceParts[0] = Number(priceParts[0]) + item.integer
唯一缺少的是整数除以 item.integer
时的余数。
const integer = Number(priceParts[0]);
const remainder = integer % item.integer;
priceParts[0] = integer + item.integer - remainder;
我们来看一个例子:
// say number = 12 and you want to round up to multiples of 5
const remainder = 12 % 5; // 2
const result = 12 + 5 - 2; // 15
上述解决方案存在两个问题。如果余数是 0
,它出现在 0、5、10、15 等处,您不想将 5
添加到数字中。否则 10
将四舍五入为 15
而 15
将四舍五入为 20
.
因此,如果余数是 0
(假),我们只使用数字,因为它已经可以被 item.integer
整除。意思是上面变成了:
const integer = Number(priceParts[0]);
const remainder = integer % item.integer;
if (remainder) {
priceParts[0] = integer + item.integer - remainder;
} else {
priceParts[0] = integer;
}
另一个问题是上面假设输入数字是正数。如果可以提供负数,则必须更改:
const remainder = integer % item.integer;
进入:
const modulo = ((integer % item.integer) + item.integer) % item.integer;
这是因为 -12
确实有 -2
的余数,所以如果您遵循相同的原则,您将得到 -12 + 5 - -2 = -5
。对于负数,我们需要取模。 -12
的模是 3
导致 -12 + 5 - 3 = -10
.
详情请参阅 remainder operator 的描述。
一个更简单的解决方案是使用 Math.floor()
、Math.round()
或 Math.ceil()
中的内置程序为您进行四舍五入。因为它四舍五入到最接近的整数,所以我们必须将整数转换为“5 的倍数”数字,对其进行四舍五入,最后将其转换回普通整数。
priceParts[0] = Math.ceil(Number(priceParts[0]) / item.integer) * item.integer;
这里的好处是 item.integer
(此处为 5)的倍数或负数没有奇怪的舍入情况。
随着整数四舍五入的方式,我个人会使用不同的方法。您可以完全使用数字值而不是专注于小数的字符串表示。
您可以使用 Math.floor(number)
获取数字的整数部分,您可以使用 (number - integer) * 100
获取小数部分。如果将小数点除以 100,则可以将小数点加到整数上,而不是将它们连接在一起。
下面的代码片段使用 find()
搜索规则数组以找到符合条件的规则。
function createRound(rules) {
return function round(num) {
const int = Math.floor(num);
const dec = (num - int) * 100;
const rule = rules.find(({start, end}) => num >= start && num <= end);
if (!rule) return num; // or throw error
const decRule = rule.decimals
.find(({start, end}) => dec >= start && dec <= end)
|| { value: dec }; // or throw error
return Math.ceil(int / rule.integer) * rule.integer
+ decRule.value / 100;
};
}
const data = {
"us": [
{
"start": 100,
"end": 200,
"integer": 5,
"decimals": [
{"start": 0, "end": 50, "value": 50},
{"start": 50, "end": 90, "value": 90},
]
}
]
};
const round = createRound(data.us);
console.log(round(101.10)); // 105.50
console.log(round(126.40)); // 130.50
console.log(round(144.60)); // 145.90
console.log(round(156.60)); // 160.90
console.log(round( 12.34)); // 12.34 (no rule)
console.log(round(156.95)); // 160.95 (no decimal rule)