从对象列表中选择唯一的子对象,并使用Ramda对其进行转换

时间:2019-07-16 14:26:15

标签: javascript ramda.js

具有以下数据结构...

const branches = [
  { id: '1', brand: { id: 'A' }},
  { id: '2', brand: { id: 'B' }},
  { id: '3', brand: { id: 'A' }}
]

我想挑选独特的品牌...这很容易。

const pickBrands = RM.pipe(
  RM.map(RM.prop('brand')),
  RM.uniqBy(RM.prop('id'))
)

但是最终,我需要改变整个事情……

const brands = [
  { id: 'A', branches: ['1', '3'] },
  { id: 'B', branches: ['2'] },
]

我有点困惑,考虑到在第一张地图之后,我正在丢失有关分支的信息,我该如何处理呢?

最终解决方案: https://runkit.com/fredyc/5d2e1bf1df8aec001aff7f64

6 个答案:

答案 0 :(得分:2)

您可以将R.groupByR.path一起使用,按brand.id进行分组,然后将R.toPairsR.mapR.zipObject一起使用,以生成新的组中的对象。

示例(由@ScottSauyet注释)

const { pipe, groupBy, path, map, pluck, toPairs, zipObj } = R

const fn = pipe(
  groupBy(path(['brand', 'id'])), //=> {"A": [{brand: {id: "A"}, id: "1"}, {brand: {id: "A"}, id: "3"}], B: [{brand: {id: "B"}, id: "2"}]}
  map(pluck('id')),               //=> {A: ["1", "3"], B: ["2"]}
  toPairs,                        //=> [["A", ["1", "3"]], ["B", ["2"]]]
  map(zipObj(['id', 'brand']) )  //=> [{id: "A", brand: ["1", "3"]}, {id: "B", brand: ["2"]}]
)

const branches = [
  { id: '1', brand: { id: 'A' } },
  { id: '2', brand: { id: 'B' } },
  { id: '3', brand: { id: 'A' } }
]

const result = fn(branches)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

注意:我最初的解决方案使用的是R.applySpec({ id: head, branches: last }),但似乎我是唯一一个更具可读性的解决方案。

答案 1 :(得分:2)

这可能也有帮助:

const group = R.pipe(
  R.groupBy(R.path(['brand', 'id'])),
  R.values,
  R.map(
    R.applySpec({ 
      id: R.path([0, 'brand', 'id']),
      branches: R.pluck('id'),
    }),
  ),
);

const branches = [
  { id: '1', brand: { id: 'A' }},
  { id: '2', brand: { id: 'B' }},
  { id: '3', brand: { id: 'A' }}
];

console.log('group', group(branches));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

答案 2 :(得分:1)

您可以使用普通的旧JS来实现结果,使用带有findIndex的reduce来检查ID是否已存在,如果存在,则将ID推送到现有对象,否则,推送新对象:

const branches = [
  { id: '1', brand: { id: 'A' }},
  { id: '2', brand: { id: 'B' }},
  { id: '3', brand: { id: 'A' }}
]

console.log(branches.reduce((a, {id, brand}) => {
  const i = a.findIndex(o => o.id === brand.id)
  i + 1 ? a[i].branches.id.push(id) : a.push({id: brand.id, branches: { id: [id] }})
  return a
}, []))

答案 3 :(得分:1)

尝试一下:

const branches = [
  { id: '1', brand: { id: 'A' }},
  { id: '2', brand: { id: 'B' }},
  { id: '3', brand: { id: 'A' }}
]  

const groupBy = (branches) => branches.reduce((acc, ele)=>( (acc[ele.brand.id] = acc[ele.brand.id] || []).push(ele), acc),{})
   
const reformat = ([k, v]) =>({id: k, branches: {id:v.map(({id})=>id)}}) 

const result = Object.entries(groupBy(branches)).map(ele => reformat(ele))

console.log(result);

答案 4 :(得分:1)

您可以使用Map来收集品牌。

const
    branches = [{ id: '1', brand: { id: 'A' } }, { id: '2', brand: { id: 'B' } }, { id: '3', brand: { id: 'A' } }],
    brands = Array.from(
        branches.reduce((m, { id: branche, brand: { id } }) =>
            m.set(id, [...(m.get(id) || []), branche]), new Map),
        ([id, branches]) => ({ id, branches: { id: branches }})
    );

console.log(brands);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 5 :(得分:1)

这是使用valuesreduceBy的解决方案。

首先让我们为品牌定义一个空模板:

const brandTmpl =
  { id: null,
    branches: [] };

然后,我们定义一个函数,该函数返回给定branch的品牌ID:

const brandId = path(['brand', 'id']);

brandId({ id: '1', brand: { id: 'A' }});
//=> 'A'

然后给定brandbranch,让我们定义一个将分支“添加”到品牌的函数:

const brand = (brd, bch) => (
  { id: brandId(bch),
    branches: append(bch.id, brd.branches) });

brand(brandTmpl, { id: '1', brand: { id: 'A' }});
//=> {id: 'A', branches: ['1']}

现在让我们使用所有这些来按品牌合并分支:

const brands = reduceBy(brand, brandTmpl, brandId);

brands([
  { id: '1', brand: { id: 'A' }},
  { id: '2', brand: { id: 'B' }},
  { id: '3', brand: { id: 'A' }}]);

//=> { A: { id: "A", branches: ["1", "3"]},
//=>   B: { id: "B", branches: ["2"]} }

最后,我们可以简单地提取值:

const branches = [
  { id: '1', brand: { id: 'A' }},
  { id: '2', brand: { id: 'B' }},
  { id: '3', brand: { id: 'A' }} ];

const brandId = path(['brand', 'id']);

const brandTmpl =
  { id: null,
    branches: [] };

const brand = (brd, bch) => (
  { id: brandId(bch),
    branches: append(bch.id, brd.branches) });

const brands = reduceBy(brand, brandTmpl, brandId);
const pickBrands = compose(values, brands);

console.log(

  pickBrands(branches)

);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {path, append, reduceBy, compose, values} = R;</script>