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

Pick unique sub-objects from list of objects and transform them with Ramda

具有以下数据结构...

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

你可以使用普通的旧 JS 来实现你的结果,使用 reduce 和 findIndex 检查 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
}, []))

试试这个:

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);

你可以拿一个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; }

可以用R.groupByR.pathbrand.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 }),但似乎我是唯一一个发现它更具可读性的人。

这可能有助于:

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>

这是使用 values and reduceBy 的解决方案。

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

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

然后让我们定义一个函数,returns 给定 branch 的品牌 ID:

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

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

然后给定一个brand和一个branch,让我们定义一个"adds"品牌分支的函数:

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>