如何从按一个值过滤的对象数组创建一个新数组?

时间:2019-08-28 06:02:40

标签: javascript arrays ecmascript-6

所以我有这个对象数组:

const dummyLinkRows = [
  {
    id: 'entity:link/1:en',
    categories: [
      {
        name: 'Human Resources'
      },
      {
        name: 'Social'
      }
    ],
    name: 'Facebook',
    url: 'https://www.facebook.com'
  },
  {
    id: 'entity:link/2:en',
    categories: [
      {
        name: 'Human Resources'
      }
    ],
    name: 'Other HR',
    url: 'https://www.hr.com'
  },
  {
    id: 'entity:link/3:en',
    categories: [
      {
        name: 'Zen Mode'
      }
    ],
    name: 'Zebra',
    url: 'https://www.zebra.com'
  },
  {
    id: 'entity:link/4:en',
    categories: [
      {
        name: 'Social'
      }
    ],
    name: 'Zebra',
    url: 'https://www.instagram.com'
  },
];

基本上,我需要按类别对链接/对象进行分组,以便为​​它们呈现对应的类别标题。

我将需要一个新数组,如下所示:

export const NEWDummyLinkRows = [
  {
    category: { name: 'Social' },
    links: [
      {
        name: 'Facebook',
        url: 'https://www.facebook.com'
      },
      {
        name: 'Instagram',
        url: 'https://www.instagram.com'
      }
    ]
  },
  {
    category: { name: 'Human Resources' },
    links: [
      {
        name: 'Other HR',
        url: 'https://www.hr.com'
      },
      {
        name: 'Zebra HR',
        url: 'https://www.zebra.com'
      }
    ]
  },  
];

这是我到目前为止在react render方法中拥有的东西:

        {props.rows &&
          props.rows.map((row, index) => {
           return (
            <div key={index}>
              <h4>{get(row, 'categories')[index].name}</h4>
              <ul className='link-group--list'>
                {row.categories.map((link, index) => {
                  return (
                    <li key={index}>
                      <a href={row.url}>
                        {link.name}
                      </a>
                    </li>
                  );
                })}
              </ul>
            </div>
          );
        })}

到目前为止,它呈现数据,但不是我需要的。我需要的方法可能是使用纯ES6 / JavaScript。

5 个答案:

答案 0 :(得分:3)

一种解决方案可能是首先还原为一个对象,然后将该对象的条目映射到您的预期结果:

const result = Object.entries(rows.reduce((a, {name, url, categories}) => {
  categories.forEach(c => {
    a[c.name] = a[c.name] || [];
    a[c.name].push({name, url});
  });

  return a;
}, {})).map(([name, links]) => ({ category: {name}, links }));

完整代码段:

const rows = [{
    id: 'entity:link/1:en',
    categories: [{
        name: 'Human Resources'
      },
      {
        name: 'Social'
      }
    ],
    name: 'Facebook',
    url: 'https://www.facebook.com'
  },
  {
    id: 'entity:link/2:en',
    categories: [{
      name: 'Human Resources'
    }],
    name: 'Other HR',
    url: 'https://www.hr.com'
  },
  {
    id: 'entity:link/3:en',
    categories: [{
      name: 'Zen Mode'
    }],
    name: 'Zebra',
    url: 'https://www.zebra.com'
  },
  {
    id: 'entity:link/4:en',
    categories: [{
      name: 'Social'
    }],
    name: 'Zebra',
    url: 'https://www.instagram.com'
  }
];

const result = Object.entries(rows.reduce((a, {name, url, categories}) => {
  categories.forEach(c => {
    a[c.name] = a[c.name] || [];
    a[c.name].push({name, url});
  });
  
  return a;
}, {})).map(([name, links]) => ({ category: {name}, links }));

console.log(result);

答案 1 :(得分:1)

您可以使用reduceMap

const dummyLinkRows = [{id: 'entity:link/1:en',categories: [{name: 'Human Resources'},{name: 'Social'}],name: 'Facebook',url: 'https://www.facebook.com'},{id: 'entity:link/2:en',categories: [{name: 'Human Resources'
}],name: 'Other HR',url: 'https://www.hr.com'},{id: 'entity:link/3:en',categories: [{name: 'Zen Mode'}],name: 'Zebra',url: 'https://www.zebra.com'},{id: 'entity:link/4:en',categories: [{name: 'Social'}],name: 'Zebra',url: 'https://www.instagram.com'}];

const final = dummyLinkRows.reduce((op,inp) => {
  let {name: nameOuter, categories, url} = inp
  categories.forEach(({name}) => {
    if(op.has(name)){
      op.get(name).links.push({name: nameOuter, url})
    } else{
      op.set(name, {catgeory:{name}, links:[{name:nameOuter, url}] })
    }
  })
  return op
},new Map())

console.log([...final.values()])

答案 2 :(得分:1)

我认为最好的方法是使用reduce。您在数组上调用.reduce,将一个函数传递给起始对象。该函数接受参数“ previous”(上一个值)和“ current”(当前数组值)并返回结果,该结果对于下一次调用该函数将是“ previous”,而在最后一次调用之后将是最终结果。 / p>

因此,请选择您的其中一个元素:

  {
    id: 'entity:link/1:en',
    categories: [
      {
        name: 'Human Resources'
      },
      {
        name: 'Social'
      }
    ],
    name: 'Facebook',
    url: 'https://www.facebook.com'
  },

您似乎想要一个具有类别对象属性的对象数组和一个具有属性类别的对象列表,该对象是具有名称的对象以及具有名称和URL的链接列表。我认为生成的对象应该是 categories 本身,仅带有名称,但无论如何。第一步,您需要使类别唯一。一个javascript对象非常适合此操作,属性名称是您的键。因此,此示例最终将被转换为:

{
  "Human Resources": {
    links: [
      { name: 'Facebook', url: 'https://www.facebook.com' }
    ]
  },
  "Social": {
    links: [
      { name: 'Facebook', url: 'https://www.facebook.com' }
    ]
  }      
}

所以我们可以从一个空对象开始。该属性将具有每个类别的名称,并且该属性的值将是带有“链接”对象数组的对象,其中包含链接的名称和网址。因此,对于原始数组中的每个元素,我们都会创建一个属性,如果该属性不像{links: []}那样存在,则该对象已经存在,我们将使用它。然后,将新链接添加到“链接”数组中。

function reducer(previous, current) {
  // previous will start as empty object and become our result, current
  // is the current element of the array we are processing

  // loop through each category
  current.categories.forEach(category => {
    // create a new object with links array if the category doesn't exist
    previous[category.name] = previous[category.name] || { links: [] };

    // add link to category
    previous[category.name].links.push({ name: current.name, url: current.url });
  });

  // return 'previous' which is our ongoing object we're creating
  return previous;
}

// call reducer for each element of our array, starting with an empty object
let intermediate = dummyLinkRows.reduce(reducer, {});

现在您拥有:

intermediate = {
  "Human Resources": {
    links: [
      { name: 'Facebook', url: 'https://www.facebook.com' }
    ]
  },
  "Social": {
    links: [
      { name: 'Facebook', url: 'https://www.facebook.com' }
    ]
  }      
}

因此,我们为每个类别创建了一个唯一的对象。为了获得最终的数组,您需要为每个类别都具有“ category”属性的项目,该属性是具有名称和我们的links数组的对象。因此,我们可以使用Object.keys来获取类别名称(对象的属性名称)的列表。使用map()将这些键转换为所需的对象:

let final = Object.keys(intermediate).map(key => {
  return {
    category: { name: key },
    links: intermediate[key];
  };
});

答案 3 :(得分:1)

以一种本机的方式,您可以像这样简单地实现

const array = [
  {
    id: 'entity:link/1:en',
    categories: [
      {
        name: 'Human Resources',
      },
      {
        name: 'Social',
      },
    ],
    name: 'Facebook',
    url: 'https://www.facebook.com',
  },
  {
    id: 'entity:link/2:en',
    categories: [
      {
        name: 'Human Resources',
      },
    ],
    name: 'Other HR',
    url: 'https://www.hr.com',
  },
  {
    id: 'entity:link/3:en',
    categories: [
      {
        name: 'Zen Mode',
      },
    ],
    name: 'Zebra',
    url: 'https://www.zebra.com',
  },
  {
    id: 'entity:link/4:en',
    categories: [
      {
        name: 'Social',
      },
    ],
    name: 'Zebra',
    url: 'https://www.instagram.com',
  },
];
const filteredArry = [];
for (let i = 0; i < array.length; i += 1) {
  const element = array[i];
  const { categories } = element;
  if (categories && Array.isArray(categories)) {
    for (let j = 0; j < categories.length; j += 1) {
      const cats = categories[j];
      const index = filteredArry.findIndex((r) => { return r.catgeory && r.catgeory.name === cats.name; });
      if (index === -1) {
        const obj = {
          catgeory: { name: cats.name },
          links: [{ name: element.name, url: element.url }],
        };
        filteredArry.push(obj);
      } else {
        const obj = { name: element.name, url: element.url };
        filteredArry[index].links.push(obj);
      }
    }
  }
}
console.log(filteredArry); 

答案 4 :(得分:0)

尝试(h = {})

dummyLinkRows.forEach(x=> x.categories.forEach(c=> 
  h[c.name] = (h[c.name]||[]).concat([{name:x.name, url:x.url}]) ))

let NEWDummyLinkRows = Object.keys(h).map(k=> ({category:k, links: h[k]}) )

const dummyLinkRows = [
  {
    id: 'entity:link/1:en',
    categories: [
      {
        name: 'Human Resources'
      },
      {
        name: 'Social'
      }
    ],
    name: 'Facebook',
    url: 'https://www.facebook.com'
  },
  {
    id: 'entity:link/2:en',
    categories: [
      {
        name: 'Human Resources'
      }
    ],
    name: 'Other HR',
    url: 'https://www.hr.com'
  },
  {
    id: 'entity:link/3:en',
    categories: [
      {
        name: 'Zen Mode'
      }
    ],
    name: 'Zebra',
    url: 'https://www.zebra.com'
  },
  {
    id: 'entity:link/4:en',
    categories: [
      {
        name: 'Social'
      }
    ],
    name: 'Zebra',
    url: 'https://www.instagram.com'
  },
];

let h={};

dummyLinkRows.forEach(x=> x.categories.forEach(c=> 
  h[c.name]=(h[c.name]||[]).concat([{name:x.name, url:x.url}]) ) )

let NEWDummyLinkRows = Object.keys(h).map(k=> ({category:k, links: h[k]}) )

console.log(NEWDummyLinkRows);