【问题标题】:Remove duplicates from array of objects but keep one property as an array从对象数组中删除重复项,但将一个属性保留为数组
【发布时间】:2019-12-17 17:41:02
【问题描述】:

我有一个这样的收藏:

const data = [
{index: 1, number: 's1', uniqId: '123', city: 'LA'},
{index: 2, number: 's2', uniqId: '321', city: 'NY'},
{index: 3, number: 's3', uniqId: '123', city: 'LA'},
{index: 4, number: 's4', uniqId: '111', city: 'TX'},
{index: 5, number: 's5', uniqId: '321', city: 'NY'}
]

我想将其分组以得到以下结果:

const data = [
{index: 1, numbers: ['s1', 's3'], uniqId: '123', city: 'LA'},
{index: 2, numbers: ['s2', 's5'], uniqId: '321', city: 'NY'},
{index: 3, number: 's4', uniqId: '111', city: 'TX'},
]

我有一个解决方案,但我相信它可以以更优雅的方式实现。我只能使用 ramda,但首选香草解决方案。 这是我的解决方案:

 return Object.values(
    data.reduce((r, e) => {
      const key = `${e.uniqId}|${e.city}`;
      if (!r[key]) {
        r[key] = e;
        if (r[key].numbers && !isEmpty(r[key].numbers)) {
          r[key].numbers.push(e.number);
        } else {
          r[key].numbers = [];
          r[key].numbers.push(e.number);
        }
      } else if (r[key].numbers && !isEmpty(r[key].numbers)) {
        r[key].numbers.push(e.number);
      } else {
        r[key].numbers = [];
        r[key].numbers.push(e.number);
      }
      return r;
    }, {}),
  ).map((item, index) => ({ ...item, index: index }));

【问题讨论】:

标签: javascript data-transform


【解决方案1】:

你做的工作比你在减速器中要做的要多

const data = [
{index: 1, number: 's1', uniqId: '123', city: 'LA'},
{index: 2, number: 's2', uniqId: '321', city: 'NY'},
{index: 3, number: 's3', uniqId: '123', city: 'LA'},
{index: 4, number: 's4', uniqId: '111', city: 'TX'},
{index: 5, number: 's5', uniqId: '321', city: 'NY'}
]

const reduced = data.reduce((acc, e) => {
  const key = `${e.uniqId}|${e.city}`;
  if (! (key in acc)) {
    acc[key] = Object.assign({}, e);
    delete acc[key]['number'];
    acc[key]['numbers'] = [];
  }
  acc[key]['numbers'].push(e.number);
  return acc;
}, {});

console.log(Object.values(reduced));

【讨论】:

    【解决方案2】:

    一个替代的 reducer 函数

    data.reduce((acc, curr) => {
      const existingIdRow = acc.find(existingElement => existingElement.uniqId === curr.uniqId);
      if(existingIdRow && existingIdRow.numbers)
        existingIdRow.numbers.push(curr.number);
      else {
        const { uniqId, city } = curr;
        acc.push({index: acc.length + 1, numbers: [curr.number], uniqId, city});
      }
      return acc
    }, [])
    

    【讨论】:

      【解决方案3】:

      嗯,是的,您可以只使用一个 reducer 和一个循环条件来完成它,所以这比获取对象的键然后循环它更快。

      const data = [
        {index: 1, number: 's1', uniqId: '123', city: 'LA'},
        {index: 2, number: 's2', uniqId: '321', city: 'NY'},
        {index: 3, number: 's3', uniqId: '123', city: 'LA'},
        {index: 4, number: 's4', uniqId: '111', city: 'TX'},
        {index: 5, number: 's5', uniqId: '321', city: 'NY'}
      ]
      
      
      const reducer = (accum, cv, currentIndex, source) => {
        const hasValue = accum.some(entry => entry.uniqId === cv.uniqId);
        // we already proccessed it.
        if (hasValue) return accum;
      
        // we create an object with the desired structure.
        const {
          index,
          uniqId,
          city,
          number
        } = cv;
        let newObj = {
          index,
          uniqId,
          city,
          numbers: [number]
        };
      
        //now lets fill the numbers :)
        source.forEach((v, index) => {
          //index !== currentIndex &&
          if (index !== currentIndex && v.uniqId === uniqId) {
            newObj['numbers'].push(v.number);
          }
        })
      
        return [...accum, newObj];
      
      }
      
      const result = data.reduce(reducer, []);
      
      console.log(result)

      【讨论】:

        【解决方案4】:

        下面是使用数组中的第一个对象作为映射和对象解构的一个非常简洁的问题:

        const data = [
        {index: 1, number: 's1', uniqId: '123', city: 'LA'},
        {index: 2, number: 's2', uniqId: '321', city: 'NY'},
        {index: 3, number: 's3', uniqId: '123', city: 'LA'},
        {index: 4, number: 's4', uniqId: '111', city: 'TX'},
        {index: 5, number: 's5', uniqId: '321', city: 'NY'}
        ]
        
        const result = data.reduce((acc, {number,uniqId,city}) => {
          if (!acc[0][uniqId]) {
            acc.push(acc[0][uniqId] = {index: acc.length, numbers: [], uniqId, city});
          }
          acc[0][uniqId].numbers.push(number);
          return acc;
        }, [{}]).slice(1);
        
        console.log(result);

        【讨论】:

          【解决方案5】:

          通常你不希望有两个不同的属性列出相似的数据,所以我做的第一件事是创建一个map() 函数来将所有number 属性更改为numbers 并将它们设为单项数组。然后我使用reduce() 函数将具有 uniqId 的 obj 组合在一起。我本来会保留它,但是由于您想要numbernumbers 的结果,具体取决于对象,我在最后写了一个简单的map() func 来转换回这种格式。

          const data = [
          {index: 1, number: 's1', uniqId: '123', city: 'LA'},
          {index: 2, number: 's2', uniqId: '321', city: 'NY'},
          {index: 3, number: 's3', uniqId: '123', city: 'LA'},
          {index: 4, number: 's4', uniqId: '111', city: 'TX'},
          {index: 5, number: 's5', uniqId: '321', city: 'NY'}
          ]
          
          
          let res = data.map((el) => {
             el.numbers = [el.number]
             delete el.number
             return el
          }).reduce((acc,cur) => {
             let ids = acc.map(obj => obj.uniqId)
             let io = ids.indexOf(cur.uniqId)
             if(io > -1){
                acc[io].numbers.push(cur.numbers[0])
             }else{
                acc.push(cur)
             }
             
             return acc
          },[])
          
          console.log(res)
          
          res = res.map(el => {
             if(el.numbers.length <= 1){
                el.number = el.numbers[0]
                delete el.numbers
             }
             return el
          })
          
          console.log(res)

          【讨论】:

            【解决方案6】:

            这是使用 Map 执行此操作的一种简单方法,并且符合您所需的输出逻辑上 - 唉,与您所需的输出相比,numbers 属性不在位置.

            如果这很重要,我把它留给你解决;)

            const data = [
              { index: 1, number: 's1', uniqId: '123', city: 'LA' },
              { index: 2, number: 's2', uniqId: '321', city: 'NY' },
              { index: 3, number: 's3', uniqId: '123', city: 'LA' },
              { index: 4, number: 's4', uniqId: '111', city: 'TX' },
              { index: 5, number: 's5', uniqId: '321', city: 'NY' }
            ];
            
            const reducer = (acc, e, idx, arr) => {
                  const key = `${e.uniqId}|${e.city}`;
                  let value = acc.get(key);
                  if (value === undefined) {  
                  	value = Object.assign({},e);    
                    acc.set(key, value);
                    value.index = acc.size;
                  } else {
                    if('number' in value) {
                  	  value.numbers = [value.number]
                      delete value.number;
                	}
                    value.numbers.push(e.number);
                  }
                  if (++idx === arr.length) {
                    return Array.from(acc.values());
                  }
                  return acc;
                };
                
            const result = data.reduce(reducer, new Map());
            document.getElementById('result').innerText = JSON.stringify(result);
            &lt;code id="result"&gt;&lt;/code&gt;

            【讨论】:

              猜你喜欢
              • 2012-05-17
              • 2019-12-12
              • 1970-01-01
              • 2017-12-31
              • 2020-04-28
              • 1970-01-01
              • 2021-06-18
              • 1970-01-01
              • 2016-03-12
              相关资源
              最近更新 更多