J. *_*ers 6 javascript functional-programming google-places-api ramda.js
我正在构建PWA,并与Ramda进行逻辑构建。我正在尝试构建给定Google Places Detail响应返回自定义地址对象的函数。
让我通过向我展示测试来在代码中描述它:
assert({
given: 'a google places api response from Google Places',
should: 'extract the address',
actual: getAddressValues({
address_components: [
{
long_name: '5',
short_name: '5',
types: ['floor'],
},
{
long_name: '48',
short_name: '48',
types: ['street_number'],
},
{
long_name: 'Pirrama Road',
short_name: 'Pirrama Rd',
types: ['route'],
},
{
long_name: 'Pyrmont',
short_name: 'Pyrmont',
types: ['locality', 'political'],
},
{
long_name: 'Council of the City of Sydney',
short_name: 'Sydney',
types: ['administrative_area_level_2', 'political'],
},
{
long_name: 'New South Wales',
short_name: 'NSW',
types: ['administrative_area_level_1', 'political'],
},
{
long_name: 'Australia',
short_name: 'AU',
types: ['country', 'political'],
},
{
long_name: '2009',
short_name: '2009',
types: ['postal_code'],
},
],
geometry: {
location: {
lat: -33.866651,
lng: 151.195827,
},
viewport: {
northeast: {
lat: -33.8653881697085,
lng: 151.1969739802915,
},
southwest: {
lat: -33.86808613029149,
lng: 151.1942760197085,
},
},
},
}),
expected: {
latitude: -33.866651,
longitude: 151.195827,
city: 'Pyrmont',
zipCode: '2009',
streetName: 'Pirrama Road',
streetNumber: '48',
},
});
Run Code Online (Sandbox Code Playgroud)
如您所见,我想要的地址对象更加“扁平”(缺少更好的术语)。我正在努力编写此转换函数。我尝试使用Ramda's做到这一点evolve,但这可以保留关键。我将需要使用Evolution来变换对象,然后reduce使用对象来扩展键。
// Pseudo
({ address_components }) => ({ ...address_components })
Run Code Online (Sandbox Code Playgroud)
我成功地evolve使用renameKeys了Ramda附件提取了相关信息,并使用Ramda附件将其重命名了,但是我不知道之后如何使该对象变平。你是怎样做的?还是有一种更简单的方法来实现所需的转换?
编辑:
我找到了实现转换的方法,但是转换很冗长。我觉得有一种更简单的方法来提取地址数据。无论如何,这是我当前的解决方案:
export const getAddressValues = pipe(
evolve({
address_components: pipe(
reduce(
(acc, val) => ({
...acc,
...{
[head(prop('types', val))]: prop('long_name', val),
},
}),
{}
),
pipe(
pickAll([
'route',
'locality',
'street_number',
'country',
'postal_code',
]),
renameKeys({
route: 'streetName',
locality: 'city',
street_number: 'streetNumber',
postal_code: 'zipCode',
}),
map(ifElse(isNil, always(null), identity))
)
),
geometry: ({ location: { lat, lon } }) => ({
latitude: lat,
longitude: lon,
}),
}),
({ address_components, geometry }) => ({ ...address_components, ...geometry })
);
Run Code Online (Sandbox Code Playgroud)
编辑:基于@codeepic的答案,这是我最终使用的普通JavaScript解决方案(尽管@ user3297291的效果很好,我喜欢它):
const getLongNameByType = (arr, type) =>
arr.find(o => o.types.includes(type)).long_name;
const getAddressValues = ({ address_components: comp, geometry: { location: { lat, lng } } }) => ({
latitude: lat,
longitude: lng,
city: getLongNameByType(comp, 'locality'),
zipCode: getLongNameByType(comp, 'postal_code'),
streetName: getLongNameByType(comp, 'route'),
streetNumber: getLongNameByType(comp, 'street_number'),
country: getLongNameByType(comp, 'country'),
});
Run Code Online (Sandbox Code Playgroud)
也许没有多大改进,但我有一些建议:
indexBy而不是(有点难以阅读)内联归约函数。juxt和mergeAll)applySpec代替pickAllrenameKeysconst { pipe, indexBy, prop, head, compose, path, map, applySpec, juxt, mergeAll } = R;
const reformatAddress = pipe(
prop("address_components"),
indexBy(
compose(head, prop("types"))
),
applySpec({
streetName: prop("route"),
city: prop("locality"),
streetNumber: prop("street_number"),
zipCode: prop("postal_code"),
}),
map(prop("long_name"))
);
const reformatLocation = pipe(
path(["geometry", "location"]),
applySpec({
latitude: prop("lat"),
longitude: prop("lng")
})
);
// Could also be: converge(mergeRight, [ f1, f2 ])
const formatInput = pipe(
juxt([ reformatAddress, reformatLocation]),
mergeAll
);
console.log(formatInput(getInput()));
function getInput() { return {address_components:[{long_name:"5",short_name:"5",types:["floor"]},{long_name:"48",short_name:"48",types:["street_number"]},{long_name:"Pirrama Road",short_name:"Pirrama Rd",types:["route"]},{long_name:"Pyrmont",short_name:"Pyrmont",types:["locality","political"]},{long_name:"Council of the City of Sydney",short_name:"Sydney",types:["administrative_area_level_2","political"]},{long_name:"New South Wales",short_name:"NSW",types:["administrative_area_level_1","political"]},{long_name:"Australia",short_name:"AU",types:["country","political"]},{long_name:"2009",short_name:"2009",types:["postal_code"]}],geometry:{location:{lat:-33.866651,lng:151.195827},viewport:{northeast:{lat:-33.8653881697085,lng:151.1969739802915},southwest:{lat:-33.86808613029149,lng:151.1942760197085}}}}; }Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>Run Code Online (Sandbox Code Playgroud)