Total Cart Price: Exercise
Write a point-free function to calculate a shopping cart’s total price in dollars.
Calculate a shopping cart’s total price in dollars.
Usage
const price = getTotalPrice(cart); // '$44.20'
cart.js
export default [{
name: 'apples',
price: 2.49
}, {
name: 'soap',
price: 1.99
}, {
name: 'milk',
price: 2.99
}, {
name: 'eggs',
price: 3.99
}, {
name: 'carrots',
price: 2.99
}, {
name: 'butter',
price: 1.49
}, {
name: 'fish',
price: 9
}, {
name: 'lettuce',
price: 2.99
}, {
name: 'broccoli',
price: 4.99
}, {
name: 'lemons',
price: 3.49
}];
index.js
用了pluck不用prop!!!!
import {pluck,prop,sum,compose,concat} from 'ramda';
import cart from './cart';
const getTotalPrice = compose(
concat("$"),//不可以 只能接受list
toString,
sum,
pluck("price")
);
Total Cart Price: Solution Review
Solution review.
We’ll cover the following
Getting Prices #
Since point-free takes some getting used to, it can help to first write a plain solution and make it point-free later.
If you need a cart’s total price and each item’s shaped like this…
{
name: 'apples',
price: 2.49
}
…start by planning how you’d initially prepare the data. It’s a collection so map can get the prices and reduce can add them up for us.
import cart from './cart';
const getTotalPrice = (items) => items
.map((item) => item.price)
.reduce((acc, value) => acc + value, 0)
const result = getTotalPrice(cart);
console.log({ result });
A Touch of Formatting #
We’d like a dollar figure, so 36.410000000000004 should be $36.41.
import cart from './cart';
const toUSD = (amount) => amount.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
const getTotalPrice = (items) => {
const total = items
.map((item) => item.price)
.reduce((acc, value) => acc + value, 0);
return toUSD(total);
};
const result = getTotalPrice(cart);
console.log({ result });
Refactoring to Point-Free #
What were our steps?
- Get each price
- Add them up
- Format as dollars (USD)
We know pipe’s great for multiple steps, so that’ll definitely help us get a point-free solution. And map/reduce are provided by Ramda.
import { map, pipe, reduce } from 'ramda';
import cart from './cart';
const toUSD = (amount) => amount.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
const getTotalPrice = pipe(
map((item) => item.price),
reduce((acc, value) => acc + value, 0),
toUSD
);
const result = getTotalPrice(cart);
console.log({ result });
Even though the map/reduce functions aren’t point-free, getTotalPrice is. This solution’s perfectly fine so pat yourself on the back if you got it.
We can make map/reduce point-free though. Ramda’s prop function grabs a given property of an object.
map(prop('price'))
And Ramda’s add function can be put inside reduce.
reduce(add, 0);
import { add, map, pipe, prop, reduce } from 'ramda';
import cart from './cart';
const toUSD = (amount) => amount.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
const getTotalPrice = pipe(
map(prop('price')),
reduce(add, 0),
toUSD
);
const result = getTotalPrice(cart);
console.log({ result });
Wait There’s More! #
Plucking a property and summing a list are such common use cases that Ramda provides functions for them!
Check out pluck and sum.
https://ramdajs.com/docs/#pluck
https://ramdajs.com/docs/#sum
import { add, pipe, pluck, sum } from 'ramda';
import cart from './cart';
const toUSD = (amount) => amount.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
const getTotalPrice = pipe(
pluck('price'),
sum,
toUSD
);
const result = getTotalPrice(cart);
console.log({ result });
I personally liked this solution the most as it’s so concise and expressive. If you got this one then double-pat yourself on the back.
toLocalString
Array.prototype.toLocaleString()
toLocaleString() 返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 “,”)隔开。
const array1 = [1, 'a', new Date('21 Dec 1997 14:12:00 UTC')];
const localeString = array1.toLocaleString('en', { timeZone: 'UTC' });
console.log(localeString);
// expected output: "1,a,12/21/1997, 2:12:00 PM",
// This assumes "en" locale and UTC timezone - your results may vary
参数
locales 可选
带有BCP 47语言标记的字符串或字符串数组,关于locales参数的形式与解释,请看Intl页面。
options 可选
一个可配置属性的对象,对于数字 Number.prototype.toLocaleString(),对于日期Date.prototype.toLocaleString().
"zh-Hans-CN" 在中国使用的简体中文 (primary language with script and country codes)
en-US
Number.prototype.toLocaleString()
toLocaleString() 方法返回这个数字在特定语言环境下的表示字符串。
新的 locales 和 options 参数让应用程序可以指定要进行格式转换的语言,并且定制函数的行为。在旧的实现中,会忽略 locales 和 options 参数,使用的语言环境和返回的字符串的形式完全取决于实现方式。
options
可选. 包含一些或所有的下面属性的类:
- “decimal” 用于纯数字格式;
- “currency” 用于货币格式;
- “percent” 用于百分比格式;
- “unit” 用于单位格式
localeMatcher
使用的 local 的匹配算法. 可能的值有 “lookup 和 “best fit”; 默认值是 “best fit”. 有关此选项更多的信息, 请参见 Intl page.
style
要使用的格式样式,默认为 “decimal”。
currency
在货币格式化中使用的货币符号. 可能的值是ISO的货币代码 (the ISO 4217 currency codes,) 例如 “USD” 表示美元, “EUR” 表示欧元, 或者 “CNY”是人民币 — 更多请参考 Current currency & funds code list。没有默认值,如果 style 是 “currency”,必须提 currency 属性.
转为美元
const toUSD = (amount) => amount.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
});
转为人民币
如:zh-u-nu-hanidec(表示中文十进制数字)
“zh-Hans-CN” 在中国使用的简体中文 (primary language with script and country codes)
const toCNY = (amount) => amount.toLocaleString('zh-Hans-CN', {
style: 'currency',
currency: 'CNY',
});
{ result: 'CN¥36.41' }