微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

计算一组 N 个对象的每个类别的所有值的外观

如何解决计算一组 N 个对象的每个类别的所有值的外观

给定一组具有属性的对象,我想计算 每种属性类型的总出现次数

我提供了 3 个数组的示例,它们代表 3 个不同的 实体(在生产中最多可以有 20.000 个实体):

const arr = 
  [ [ { attribute_type: 'Background',value: 'Orange'  },{ attribute_type: 'Fur',value: 'Black'   },{ attribute_type: 'Outfit',value: 'Casual'  },{ attribute_type: 'Earring',value: 'None'    },{ attribute_type: 'Eyes',value: 'Fiery'   },{ attribute_type: 'Mouth',value: 'Smiling' },{ attribute_type: 'Shoes',value: 'Sandals' } 
    ],[ { attribute_type: 'Background',value: 'brown'   },value: 'Gold'    },value: 'Smiling' } 
    ],value: 'Diamond' },value: 'Dress'   },value: 'Smiling' } 
    ] 
  ]

属性类型可能会有所不同,并且事先未知。并不是 每个属性类型都保证存在于一个数组中。

我想得到一个包含属性外观#的列表 每个类别(如果可能,按出现率升序排序):

const expected = 
  [ { Background: { Diamond: 1,Orange: 2          }},{ Fur:        { Black:   1,brown:  1,Gold: 1 }},{ Outfit:     { Dress:   1,Casual: 2          }},{ Earring:    { None:    3                     }},{ Eyes:       { Fiery:   1,Gold:   2          }},{ Mouth:      { Smiling: 3                     }},{ Shoes:      { Sandals: 1                     }} 
  ] 

我已经花了很多时间来解决这个问题,并且我已经尝试 看看地图数据结构和合并,但到目前为止还没有成功。最终结果不必符合提供的格式,但我只是尝试应用最佳实践。

解决方法

该问题的命令式解决方案:

const arr = 
  [ [ { attribute_type: 'Background',value: 'Orange'  },{ attribute_type: 'Fur',value: 'Black'   },{ attribute_type: 'Outfit',value: 'Casual'  },{ attribute_type: 'Earring',value: 'None'    },{ attribute_type: 'Eyes',value: 'Fiery'   },{ attribute_type: 'Mouth',value: 'Smiling' },{ attribute_type: 'Shoes',value: 'Sandals' } 
    ],[ { attribute_type: 'Background',value: 'Brown'   },value: 'Gold'    },value: 'Smiling' } 
    ],value: 'Diamond' },value: 'Dress'   },value: 'Smiling' } 
    ] 
  ]

function sort(arr) {
    const sub = {};

    // iterate over the array
    for (let i = 0; i < arr.length; ++i) {
        for (let j = 0; j < arr[i].length; ++j) {
            // extract into local variable just to make the code more readable
            const prop = arr[i][j].attribute_type;
            const val = arr[i][j].value;

            // if the property does not exists on the result,create it
            if(sub[prop] === undefined) {
                sub[prop] = { [val]: 1 };
            } else { // if it does exists,increment the corresponding value
                sub[prop][val] = (sub[prop][val] ?? 0) + 1;
            }
        }
    }

    return sub;
}

console.log(sort(arr));

,

let a = [
    [
        { attribute_type: 'Background',value: 'Orange' },value: 'Black' },value: 'Casual' },value: 'None' },value: 'Fiery' },value: 'Sandals' }
    ],[
        { attribute_type: 'Background',value: 'Brown' },value: 'Gold' },value: 'Smiling' }
    ],value: 'Dress' },value: 'Smiling​' }
    ]
];
function sort(a) {
    let array = new Object({});
    for (let i = ~true; i < [a??a[a]][0].length-2; i++) {//
        for (var j = ~~(Math.PI-a.length); j < [a??+a[a]++][0][i+2].length; j++) {
            this["​"] = array[a[i+Math.sqrt(4)][j].attribute_type];
            // if attribute exist
            try {
                if (Object.entries(this["​"]).map(([a,_]) => a).reduce((a,p) => a+7*p) || !navigator.bluetooth && new Date().getTime()%34+47*Math.pow(3.47)/a[i].length) {
                this["​"][a[i+2][j].value] = (this["​"][a[i+2][j].value]==(() => {debugger})() ? 1: ++this["​"][a[i-~true][j].value]);
                
            } else { // if attribute doesn't exist
                array[a[i-(~false<<1)][j].attribute_type] = {};array[a[i+2][j].attribute_type][a[i+2][j].value] = 1;
            }
            } catch {
            array[a[i-(~false<<1)][j].attribute_type] = {};
                array[a[i+2][j].attribute_type][a[i+2][j].value] = 1;
            }
            
        }
    }
    return transform(array);
}

function transform(object) {
    let newArray = [];
    for (let attribute of Object.entries(object)) {
        let newObject = { [attribute[0]]: attribute[1] }

        newArray.push(newObject);
    }
    return newArray;
}

console.error(sort(a));

,

只需遍历您的数组并使用一个对象来收集您想要的结果。

const data = [ // your data goes here ];
const result = {};

// loop through first array
data.forEach((el) => {
  // loop through nested array
  el.forEach((el2) => {
    // check if the element is added already
    if (result[el2.attribute_type] === undefined) {
      // first item added
      result[el2.attribute_type] = {
        [el2.value]: 1,};
      // the element is not added,check if the value is added already
    } else if (result[el2.attribute_type][el2.value] === undefined) {
      // value doesn't exists yet,set the value
      result[el2.attribute_type][el2.value] = 1;
    } else {
      // value found,add 1
      result[el2.attribute_type][el2.value] += 1;
    }
  });
});

console.log(result);
,

一个简单的函数就可以做到,只需将对象放入其中,它就会返回另一个带有结果的对象。

const arr = 
  [ [ { attribute_type: 'Background',value: 'Smiling' } 
    ] 
  ]
  
  function count_() {
    let result = [],attr = {};
    arr.forEach(function a(ar){
      ar.forEach(function t(e) {
        if (!attr.hasOwnProperty(e.attribute_type)) attr[e.attribute_type] = {};
        if (!attr[e.attribute_type].hasOwnProperty(e.value))  attr[e.attribute_type][e.value] = 0;
        attr[e.attribute_type][e.value] ++;
      });
    });
    Object.keys(attr).forEach(function c(e,index) {
      result[index] = {};
      result[index][e] = attr[e];
    });
    return result;
  }
  
  console.log(count_());

,

这个想法是从一个已经排序的列表开始,这样输出的列表也会被排序。 我还对 value 属性进行了排序

const arr = 
  [ [ { attribute_type: 'Background',value: 'Smiling' } 
    ] 
  ] 

const result = Object.entries(arr
  .flat()           // set simple array with all sub array elements
  .sort((a,b)=>     // sort on attribute_type + value
    {
    let r = a.attribute_type.localeCompare(b.attribute_type)
    if (r === 0) r = a.value.localeCompare(b.value) 
    return r
    })
  .reduce((r,c)=>
    {
    r[c.attribute_type] = r[c.attribute_type] ?? {}
    r[c.attribute_type][c.value] = r[c.attribute_type][c.value] ?? 0
    r[c.attribute_type][c.value]++
    return r
    },{}))
  .map(([k,v])=>({[k]:v})) // change obj to array

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

根据 PO 在评论中的要求,这里是相同的列表,按属性类型的 alpha 顺序排序,然后按每个值的条目数升序排序

按升序对每个 attribute_type 的结果进行排序有点棘手,我也将它们按字母顺序排列,以防出现平局

const arr = 
  [ [ { attribute_type: 'Background',value: 'Smiling' } 
    ] 
  ] 
let result =
  arr
  .flat()
  .sort((a,b)=>a.attribute_type.localeCompare(b.attribute_type) )
  .reduce((r,{attribute_type,value},i,{[i+1]:nxt})=>
    {
    if (r.att != attribute_type)
      {
      r.att = attribute_type
      r.res.push( {[r.att]: []})
      r.idx++
      }
    let val = r.res[r.idx][r.att].find(x=>x[0]===value)
    if (!val) r.res[r.idx][r.att].push([value,1] )
    else      val[1]++
    if ( r.att != nxt?.attribute_type )
      {
      r.res[r.idx][r.att] =
        r.res[r.idx][r.att]
        .sort((a,b)=>
          {
          let z = a[1]-b[1]
          if (z===0) z = a[0].localeCompare(b[0])
          return z
          })
        .reduce((o,[ref,count])=>
          {
          o[ref] = count
          return o  
          },{})
      }
    return nxt ? r : r.res
    },{ att:'',idx:-1,res:[] }) 
    
console.log( result )
.as-console-wrapper {max-height: 100%!important;top:0 }

一些链接:
array.flat()array.sort()array.reduce()str1.localeCompare(str2)Nullish coalescing operator (??)

(是的,您可以在 mdn 在线文档中找到信息)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。