[英]Use Ramda to Multiply and transform objects of an array based on a key name pattern. Return all in new flat array
我有一个对象数组,其中每个 object 都有重复的“翻译”键和不同语言的翻译值,但也有正常的通用值,如价格。
[
{name_de: 'foo 1 de', name_it: 'foo 1 it', price: 10 },
{name_de: 'foo 2 de', name_it: 'foo 2 it', price: 20 },
{name_de: 'foo 3 de', name_it: 'foo 3 it', price: 30 }
]
我需要将每个 object 乘以包含其他语言值的附加对象,键应该在没有语言后缀为“名称”的情况下进行规范化。 像价格这样的通用道具应该仍然存在,
应该像这样转换成一个新数组
[
{
"name": "foo 1 de",
"price": 10
},
{
"name": "foo 1 it",
"price": 10
},
{
"name": "foo 2 de",
"price": 20
},
{
"name": "foo 2 it",
"price": 20
},
{
"name": "foo 3 de",
"price": 30
},
{
"name": "foo 3 it",
"price": 30
},
]
我正在玩 R.flatten 和 R.groupBy 但我没有得到任何结果。
有没有聪明的解决方案?
这将处理带有两个日期代码字母的多个键的对象(即_de
)——我添加了一个日期属性作为示例。
它将每个 object 转换为一对数组。 按语言代码对对进行分组,然后对每个语言代码项进行 map,将它们与 generics 组合,并将对转换回对象。
const { pipe, toPairs, groupBy, head, match, last, converge, omit, values, prop, adjust, replace, flip, concat, fromPairs, map } = R; const pattern = /_([az]{2})$/; const splitByCode = R.chain(pipe( toPairs, groupBy(pipe(head, match(pattern), last)), // group by the lang code converge((lang, gen) => map( pipe( map(adjust(0, replace(pattern, ''))), // remove language code from the 1st item in each pair flip(concat)(gen), // combine with the generics fromPairs // convert to object ), lang ), [ pipe(omit(['undefined']), values), // get all pairs with language code prop(['undefined']) // get all pairs without language code ] ) )); const data = [{"name_de":"foo 1 de","date_de":"date 1 de","date_it":"date 1 it","name_it":"foo 1 it","price":10},{"name_de":"foo 2 de","date_de":"date 2 de","date_it":"date 1 it","name_it":"foo 2 it","price":20},{"name_de":"foo 3 de","date_de":"date 3 de","date_it":"date 1 it","name_it":"foo 3 it","price":30}]; const result = splitByCode(data); console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
我可能会做这样的事情:
const separateCountries = chain (x => { const [countries, others] = partition (test (/_[az]{2}$/), keys (x)) return map (k => ({[k.slice(0, -3)]: x [k], ... pick (others, x)}), countries) }) const prices = [{name_de: 'foo 1 de', name_it: 'foo 1 it', price: 10 }, {name_de: 'foo 2 de', name_it: 'foo 2 it', price: 20 }, {name_de: 'foo 3 de', name_it: 'foo 3 it', price: 30 }] console.log (separateCountries (prices))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script> <script>const {chain, partition, test, keys, map, pick} = R </script>
这将每个看起来像name_ab
的键分开,并在每个结果上保留所有看起来不像的属性。 它使用partition
对它们进行正确分组。
这里的chain
、 test
、 keys
和map
调用可以很容易地被原生 JS 特性所取代。 但是对partition
和pick
的调用可能只能通过在您自己的代码中构建相同的功能来代替。
请注意,它相当通用,例如不关心name
,只是键以_
和两个字母结尾。 该密钥的其余部分成为生成的 object 中的密钥。
受到OriDrori 答案的启发,我想要一个具有相同行为的版本,这样如果有其他国家级字段以及name
,那么它们将全部组合到一个国家 object 中。
它不像我最初的答案那么简单,但仍然不算太糟糕。 它是该无点实现的有趣替代方案。
const separateCountries = chain (( x, [countries, others] = partition (test (/_[az]{2}$/), keys (x)), base = pick(others, x) ) => map ( merge(base), map ( compose (mergeAll, map (k => ({[slice (0, -3, k)]: x [k]}))), values (groupBy (slice (-2, Infinity), countries)) ) )) const prices = [{"name_de":"foo 1 de", "whatit_us": "whatsit 1 us", "date_de":"date 1 de","date_it":"date 1 it","name_it":"foo 1 it","price":10},{"name_de":"foo 2 de","date_de":"date 2 de","date_it":"date 1 it","name_it":"foo 2 it","price":20},{"name_de":"foo 3 de","date_de":"date 3 de","date_it":"date 1 it","name_it":"foo 3 it","price":30}] console.log (separateCountries (prices))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script> <script>const {chain, partition, test, keys, pick, map, merge, mergeAll, compose, slice, values, groupBy} = R</script>
您在这里不需要 Ramda – 简单的现代 JavaScript 足够简洁。
// Split a key to its non-localized prefix and localization; return null if not localized.
// Can be customized as required.
function splitKey(key) {
const bits = key.split("_");
if (bits.length > 1) return bits;
return null;
}
function generateNonlocalizedObjects(destArray, sourceObj) {
const localizedKeys = [];
const nonLocalizedData = {};
Object.keys(sourceObj).forEach(key => {
const value = sourceObj[key];
const keyBits = splitKey(key);
if (keyBits !== null) {
localizedKeys.push([keyBits[0], keyBits[1], value]);
} else {
nonLocalizedData[key] = value;
}
});
if (!localizedKeys.length) {
// No localized data; just push the data onto the array.
destArray.push(nonLocalizedData);
return;
}
localizedKeys.forEach(([key, locale, value]) => {
// Merge the non-localized data with the rest
destArray.push({ ...nonLocalizedData, [key]: value, $locale: locale });
});
}
const inputObjects = [
{ name_de: "foo 1 de", name_it: "foo 1 it", price: 10 },
{ name_de: "foo 2 de", name_it: "foo 2 it", price: 20, blep: 33 },
{ name_de: "foo 3 de", name_it: "foo 3 it", price: 30, blur: 99 },
];
const destArray = [];
inputObjects.forEach(iobj => generateNonlocalizedObjects(destArray, iobj));
console.log(destArray);
输出
[
{ price: 10, name: 'foo 1 de', '$locale': 'de' },
{ price: 10, name: 'foo 1 it', '$locale': 'it' },
{ price: 20, blep: 33, name: 'foo 2 de', '$locale': 'de' },
{ price: 20, blep: 33, name: 'foo 2 it', '$locale': 'it' },
{ price: 30, blur: 99, name: 'foo 3 de', '$locale': 'de' },
{ price: 30, blur: 99, name: 'foo 3 it', '$locale': 'it' }
]
– 如果你不需要$locale
那里,摆脱它。 :)
同样,您可能希望自定义splitKey()
以更仔细地查看键,并且仅在它以“已知语言环境”( en
、 de
、 it
……)结尾时才拆分它。
它不是 ramda,但它不是很长或很复杂。
const input = [ {name_de: 'foo 1 de', name_it: 'foo 1 it', price: 10 }, {name_de: 'foo 2 de', name_it: 'foo 2 it', price: 20 }, {name_de: 'foo 3 de', name_it: 'foo 3 it', price: 30 } ] const output = input.reduce((acc, el) => { const names = [], cmn = {}; Object.keys(el).forEach(n => { n.startsWith("name")? names.push(el[n]): cmn[n] = el[n]; }); names.forEach(n => acc.push({name: n, ...cmn})); return acc; }, []); console.log(output);
可以使用reduce
方法来完成:
let sourceData =[
{name_de: 'foo 1 de', name_it: 'foo 1 it', price: 10 },
{name_de: 'foo 2 de', name_it: 'foo 2 it', price: 20 },
{name_de: 'foo 3 de', name_it: 'foo 3 it', price: 30 }
];
const result = sourceData.reduce((a,c) => {
a.push({name: c.name_de, price: c.price});
a.push({name: c.name_it, price: c.price});
return a;
}, [])
console.log(result);
这可以满足您的要求,但是 ramda 仅少量使用...
const languages = ['de', 'it'].map(l => `name_${l}`); const parseLabels = (base, labels) => R.reduce( (res, name) => res.concat( R.mergeRight(base, { name }), ), [], labels, ); const parseItem = R.converge(parseLabels, [ R.pick(['price']), R.pipe(R.pick(languages), R.values), ]); const parse = R.reduce( (res, item) => res.concat( parseItem(item), ), [], ); const data = [ {name_de: 'foo 1 de', name_it: 'foo 1 it', price: 10 }, {name_de: 'foo 2 de', name_it: 'foo 2 it', price: 20 }, {name_de: 'foo 3 de', name_it: 'foo 3 it', price: 30 }, ]; console.log('result', parse(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>
我会为此使用换能器:
对于每个 object:
values({name_de: 'foo 1 de', name_it: 'foo 1 it', price: 10})
//=> ['foo 1 de', 'foo 1 it', 10]
splitAt(-1, ['foo 1 de', 'foo 1 it', 10])
//=> [['foo 1 de', 'foo 1 it'], [10]]
apply(xprod)([['foo 1 de', 'foo 1 it'], [10]])
//=> [['foo 1 de', 10], ['foo 1 it', 10]]
lift(zipObj(['name', 'price']))([['foo 1 de', 10], ['foo 1 it', 10]])
//=> [{name: "foo 1 de", price: 10}, {name: "foo 1 it", price: 10}]
const splitObjects = into([], compose( map(values), map(splitAt(-1)), map(apply(xprod)), map(lift(zipObj(['name', 'price']))) )); console.log(flatten(splitObjects(items)))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script> <script>const {into, compose, map, values, splitAt, apply, xprod, lift, zipObj, flatten} = R</script> <script> const items = [ {name_de: 'foo 1 de', name_it: 'foo 1 it', price: 10 }, {name_de: 'foo 2 de', name_it: 'foo 2 it', price: 20 }, {name_de: 'foo 3 de', name_it: 'foo 3 it', price: 30 } ]; </script>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.