【问题标题】:Get unique values from array of objects从对象数组中获取唯一值
【发布时间】:2019-02-28 14:11:03
【问题描述】:

我有一个这样的动态对象数组:

var arr = [
    {state: "FL"},
    {state: "NY"},
    {state: "FL"},
    {gender: "Male"},
    {state: "NY"},
    {gender: "Female"},
    {gender: "Female"},
    {year: "1990"}
]

我怎样才能得到唯一的对象?

所需的输出是一个仅包含唯一对象的数组:

arr = [
    {state: "FL"},
    {state: "NY"},
    {gender: "Male"},
    {gender: "Female"},
    {year: "1990"}
]

我正在尝试使用 reduce 进行类似的操作,但这样我需要知道对象键:

arr = arr.reduce((acc, curr) => 
    acc.find(e => e['state'] === curr['state']) ? acc : [...acc, curr], [])

这不是重复的,因为其他问题没有使用“动态对象”来获得唯一性

【问题讨论】:

  • 想要的输出是什么?
  • .find(e => JSON.stringify(e) === JSON.stringify(curr)) 将是一种快速而肮脏的方式。
  • 您的对象是否总是只有一个带有字符串值的键?如果没有,你能告诉我更多关于它们的信息吗,所以我可以尝试给出一个具体的解决方案,而不是使用 JSON.stringify,这对于一个大数组来说可能会很慢。
  • 对象可以有多个键,但值始终是字符串。 var arr = [ {state: "FL", year: "1980", class: "A"}, {state: "NY"}, {state: "FL"}, {gender: "Male"}, {state : "NY"}, {gender: "Female"}, {gender: "Female"}, {year: "1990"} ]

标签: javascript unique


【解决方案1】:

您可以对所有对象进行字符串化,获取唯一的 JSON,然后将字符串转换回对象。

var array = [{ state: "FL" }, { state: "NY" }, { state: "FL" }, { gender: "Male" }, { state: "NY" }, { gender: "Female" }, { gender: "Female" }, { year: "1990" }],
    unique = Array.from(
        new Set(array.map(o => JSON.stringify(o))),
        s => JSON.parse(s)
    );
    
console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }

如果对象中有多个键,并且因为如果对象的键顺序不同,我建议您先获取条目,对该数组进行排序,将其字符串化为一组,然后获取新对象回来了。

var array = [{ foo: 42, state: "FL" }, { state: "FL", foo: 42 }, { state: "FL" }, { state: "NY" }, { state: "FL" }, { gender: "Male" }, { state: "NY" }, { gender: "Female" }, { gender: "Female" }, { year: "1990" }],
    unique = Array.from(
        new Set(array.map(o => JSON.stringify(Object.entries(o).sort(([a], [b]) => a.localeCompare(b))))),
        s => Object.assign({}, ...JSON.parse(s).map(([k, v]) => ({ [k]: v })))
    );
    
console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

    【解决方案2】:

    您可以 reduce 到一个对象,其中对象中的每个值都是该对象中的一个键(因为对象不能在键上加倍 - 因此允许您获得唯一值),然后将其与 @987654322 一起使用@ 以像这样获取缩减对象中的值:

    const arr = [{state: "FL"},{state: "NY"},{state: "FL"},{gender: "Male"},{state: "NY"},{gender: "Female"},{gender: "Female"},{year: "1990"}]
    const res = Object.values(arr.reduce((acc, obj) => {
      const [[key, val]] = Object.entries(obj);
      return (acc[val] = {[key]: val}, acc);
    }, {}));
    
    console.log(res);

    【讨论】:

      【解决方案3】:

      考虑到给定对象的简单性,我想到的快速方法

      1. 使用JSON.stringify将所有对象转换为字符串
      2. 通过将该字符串数组转换为set 来获取所有唯一值
      3. 再次将字符串转换为对象

      var arr = [{state: "FL"},{state: "NY"},{state: "FL"},{gender: "Male"},{state: "NY"},{gender: "Female"},   {gender: "Female"},{year: "1990"}
      ]
      
      const stringArr = arr.map(str => JSON.stringify(str));
      const uniqueStrs = [ ...new Set(stringArr)] // removes duplicates
      const result = uniqueStrs.map(str => JSON.parse(str));
      
      console.log(result);

      【讨论】:

        【解决方案4】:

        我知道,我知道,我也是……但我的回答更简洁一些。

        [...new Set(arr.map(JSON.stringify))].map(JSON.parse);
        

        这有使用JSON.stringify 的常见警告,即根据规范,您不能依赖键的顺序来保持一致。如果您只有一个密钥,这将永远不会成为问题。如果每个对象都是通过按相同顺序添加键来构造的,这也可能不是问题,因为大多数实现都会保留键添加顺序。

        【讨论】:

          【解决方案5】:

          这个性能比使用 JSON.parse 和 stringify 的任何东西都要好。

          var arr = [
              {state: "FL"},
              {state: "NY"},
              {state: "FL"},
              {gender: "Male"},
              {state: "NY"},
              {gender: "Female"},
              {gender: "Female"},
              {year: "1990"}
          ];
          
          const unique = arr => arr.filter((item, index) => !arr.some((i, idx) => idx > index && Object.getOwnPropertyNames(item).every(property => i[property] === item[property])));
          
          console.log(unique(arr));

          或者像你尝试的那样使用 reduce 而不是过滤器

          var arr = [
              {state: "FL"},
              {state: "NY"},
              {state: "FL"},
              {gender: "Male"},
              {state: "NY"},
              {gender: "Female"},
              {gender: "Female"},
              {year: "1990"}
          ];
          
          const unique = arr => arr.reduce((results, item) => {
            if (!results.some(i => Object.getOwnPropertyNames(item).every(property => i[property] === item[property]))) {
              results.push(item);
            }
            return results;
          }, []);
          
          console.log(unique(arr));

          【讨论】:

            【解决方案6】:

            这应该可以工作

            const arr = [
              { state: 'FL' },
              { state: 'NY' },
              { state: 'FL' },
              { gender: 'Male' },
              { state: 'NY' },
              { gender: 'Female' },
              { gender: 'Female' },
              { year: '1990' },
            ];
            
            arr.reduce((array, obj) => {
              for (const target of array) {
                if (JSON.stringify(target) === JSON.stringify(obj)) {
                  return array;
                }
                return [...array, obj];
              }
            }, []);

            【讨论】:

              【解决方案7】:

              有很多方法可以做到这一点:这里有两种:

              1. reduce
              2. for loop

              var arr = [
                  {state: "FL"},
                  {state: "NY"},
                  {state: "FL"},
                  {gender: "Male"},
                  {state: "NY"},
                  {gender: "Female"},
                  {gender: "Female"},
                  {year: "1990"}
              ]
              
              //two solutions
              //1. reduce and some
              let arr1 = arr.reduce( (acc, currentValue) => {
                  const key = Object.keys(currentValue)[0]; //we only have one property!
                  const inArr = acc.some((element) => {return element[key] == currentValue[key]});
                  if (!inArr)
                  {
                    acc.push(currentValue);
                  }
                  return acc;
              
                },[]);
              
              console.log(arr1);
              
              //2. for loop
              //you can still do a for loop (Quick):
              const shadow = [];
              const iMax= arr.length;
              for (let i = 0; i < iMax; i++)
              {
                 const key = Object.keys(arr[i])[0]; //we only have one property!
                //check if value is not in shadow array
                if (shadow.indexOf(arr[i][key]) == -1)
                {
                  arr.push(arr[i]);
                  shadow.push(arr[i][key]);
                }
              }
              //splice off the original values
              arr.splice(0, iMax);
              console.log(arr);

              【讨论】:

                【解决方案8】:

                使用filter 方法:

                var arr = [ 
                  {state: "FL"}, {state: "NY"}, {state: "FL"}, {gender: "Male"},
                  {state: "NY"}, {gender: "Female"}, {gender: "Female"}, {year: "1990"}
                ]
                
                var len = arr.length ;
                var result = [] ;
                
                var result = arr.filter( (cur, inx) => {
                  var same = 0 ;
                  var curKey = Object.keys(cur)[0] ;
                  for ( var i = inx + 1; i < len; i++ ) 
                    if ( cur[curKey] === arr[i][curKey] ) { same++; break; }
                  return !same;
                })
                
                console.log( result ) ;

                【讨论】:

                  猜你喜欢
                  • 2020-11-13
                  • 2019-10-20
                  • 1970-01-01
                  • 2019-01-03
                  • 2019-11-14
                  • 2022-01-10
                  • 2020-07-14
                  • 2021-10-30
                  相关资源
                  最近更新 更多