繁体   English   中英

使用 Ramda 根据键名模式对数组对象进行乘法和变换。 在新的平面数组中返回所有内容

[英]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对它们进行正确分组。

这里的chaintestkeysmap调用可以很容易地被原生 JS 特性所取代。 但是对partitionpick的调用可能只能通过在您自己的代码中构建相同的功能来代替。

请注意,它相当通用,例如不关心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()以更仔细地查看键,并且仅在它以“已知语言环境”( endeit ……)结尾时才拆分它。

它不是 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:

  1. 取出值:
values({name_de: 'foo 1 de', name_it: 'foo 1 it', price: 10})
//=> ['foo 1 de', 'foo 1 it', 10]
  1. 单独的标签和价格:
splitAt(-1, ['foo 1 de', 'foo 1 it', 10])
//=> [['foo 1 de', 'foo 1 it'], [10]]
  1. 将价格与每个 label 配对:
apply(xprod)([['foo 1 de', 'foo 1 it'], [10]])
//=> [['foo 1 de', 10], ['foo 1 it', 10]]
  1. 最后将这些对与键配对以创建对象:
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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM