如果属性值为true,则按多个属性分组

Lodash group by multiple properties if property value is true

本文关键字:属性 true 如果      更新时间:2023-09-26

我有一个车辆数组,只有当'selected'属性为真时,才需要按make和model进行分组。结果对象应该包含make model和count的属性。使用lodash,我如何将车辆对象组织为所需的结果对象。我能够获得由makeCode分组的车辆对象,但我不确定如何通过多个属性分组。

集团通过使代码作品

      var vehicles = _.groupBy(response.vehicleTypes, function(item)
      {
        return item.makeCode; // how to group by model code as well
      });

初始车辆

{
    id: 1, 
    selected: true, 
    makeCode: "Make-A", 
    modelCode: "Model-a", 
    trimCode: "trim-a", 
    yearCode: "2012"
},
{
    id: 2, 
    selected: false, 
    makeCode: "Make-A", 
    modelCode: "Model-a", 
    trimCode: "trim-a", 
    yearCode: "2013"
},
{
    id: 3, 
    selected: true, 
    makeCode: "Make-B", 
    modelCode: "Model-c", 
    trimCode: "trim-a", 
    yearCode: "2014"
},
{
    id: 25, 
    selected: true, 
    makeCode: "Make-C", 
    modelCode: "Model-b", 
    trimCode: "trim-b", 
    yearCode: "2012"
},
{
    id: 26, 
    selected: true, 
    makeCode: "Make-C", 
    modelCode: "Model-b", 
    trimCode: "trim-a", 
    yearCode: "2013"
}

结果对象

{
    Make-A: {
        Model-a: {
            count: 1
        }
    }
},
{
    Make-B: {
        Model-c: {
            count: 1
        }
    }
},
{
    Make-C: {
        Model-b: {
            count: 2
        }
    }
}

我不确定这是否会解决您的问题,但在group_by中,您可以添加自定义逻辑,允许您创建复合键。

请记住,分隔符值应该根据您使用的数据源来定义,如果"——"字符出现在模型或类型中,您不应该使用它们,因为它将不允许您逆转分组过程。

const SEPERATOR = "--";
_.chain(data).filter((item) => item.selected).groupBy((item)=>`${item.model}${SEPERATOR}${item.type}`).value();

既然已经使用了lodash,那么可以利用_。过滤功能。这将只返回selected为真的项。

var selectedVehicles = _.filter(response.vehicleTypes, 'selected');

现在您有了selectedVehicles数组,您可以使用原始代码按makeCode进行分组。

selectedVehicles = _.groupBy(selectedVehicles, function(item) {
  return item.makeCode;
});

返回一个对象,因此我们需要遍历这些键,并执行第二个groupBy

_.forEach(selectedVehicles, function(value, key) {
  selectedVehicles[key] = _.groupBy(selectedVehicles[key], function(item) {
    return item.modelCode;
  });
});

从这里你将得到一个形式的对象。我将让您从每个数组中获取计数。

{ 'Make-A': { 'Model-a': [ ... ] },
  'Make-B': { 'Model-c': [ ... ] },
  'Make-C': { 'Model-b': [ ..., ... ] } }

如果你关注结果,下面的代码可以工作:

在我的例子中,BrandItem Code是属性

const products = _.groupBy(this.productsTable.data, (item) => {
    return [item['Brand'], item['Item Code']];
});

您可以使用Array.prototype.reduce(),并在一个循环中完成O(n):

var arr = [{"id":1,"selected":true,"makeCode":"Make-A","modelCode":"Model-a","trimCode":"trim-a","yearCode":"2012"},{"id":2,"selected":false,"makeCode":"Make-A","modelCode":"Model-a","trimCode":"trim-a","yearCode":"2013"},{"id":3,"selected":true,"makeCode":"Make-B","modelCode":"Model-c","trimCode":"trim-a","yearCode":"2014"},{"id":25,"selected":true,"makeCode":"Make-C","modelCode":"Model-b","trimCode":"trim-b","yearCode":"2012"},{"id":26,"selected":true,"makeCode":"Make-C","modelCode":"Model-b","trimCode":"trim-a","yearCode":"2013"},{"id":29,"selected":false,"makeCode":"Make-A","modelCode":"Model-g","trimCode":"trim-a","yearCode":"2013"},{"id":2,"selected":true,"makeCode":"Make-A","modelCode":"Model-h","trimCode":"trim-a","yearCode":"2013"}];
var result = arr.reduce(function(map, obj) {
  if(!obj.selected) {
    return map;
  }
  
  var makeCode = map[obj.makeCode] = map[obj.makeCode] || {};
  
  var modelCode = makeCode[obj.modelCode] = makeCode[obj.modelCode] || { count: 0 };
  
  modelCode.count++;
  
  return map;
}, Object.create(null));
console.log(result);

使用解构的更可读、更现代的版本:

const arr = [{"id":1,"selected":true,"makeCode":"Make-A","modelCode":"Model-a","trimCode":"trim-a","yearCode":"2012"},{"id":2,"selected":false,"makeCode":"Make-A","modelCode":"Model-a","trimCode":"trim-a","yearCode":"2013"},{"id":3,"selected":true,"makeCode":"Make-B","modelCode":"Model-c","trimCode":"trim-a","yearCode":"2014"},{"id":25,"selected":true,"makeCode":"Make-C","modelCode":"Model-b","trimCode":"trim-b","yearCode":"2012"},{"id":26,"selected":true,"makeCode":"Make-C","modelCode":"Model-b","trimCode":"trim-a","yearCode":"2013"},{"id":29,"selected":false,"makeCode":"Make-A","modelCode":"Model-g","trimCode":"trim-a","yearCode":"2013"},{"id":2,"selected":true,"makeCode":"Make-A","modelCode":"Model-h","trimCode":"trim-a","yearCode":"2013"}];
const result = arr.reduce((acc, { selected, makeCode, modelCode }) => {
  if(!selected) return acc;
  
  if(!acc[makeCode]) acc[makeCode] = {};
  
  const make = acc[makeCode];
  
  if(!make[modelCode]) make[modelCode] = { count: 0 };
  
  make[modelCode].count++;
  
  return acc;
}, Object.create(null));
console.log(result);

const result = _.chain(vehicles)
.filter('selected')
.groupBy('makeCode')
.mapValues(values => _.chain(values)
    .groupBy('modelCode')
    .mapValues(_.size)
    .value()
)
.value()

const multiGroupBy = (array, group, ...restGroups) => {
  if(!group) {
    return array;
  }
  const currGrouping = _.groupBy(array, group);
  if(!restGroups.length) {
    return currGrouping;
  }
  return _.transform(currGrouping, (result, value, key) => {
    result[key] = multiGroupBy(value, ...restGroups);
  }, {});
};
console.log(multiGroupBy([{x:1,y:1,z:1},{x:1,y:2,z:1},{x:2,y:1,z:1},{x:2,y:2,z:1},{x:1,y:1,z:2},{x:1,y:2,z:2},{x:2,y:1,z:2},{x:2,y:2,z:2}],'x','y'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

或者如果你喜欢旧语法

function multiGroupBy(array, group) {
  if(!group) {
    return array;
  }
  var currGrouping = _.groupBy(array, group);
  var restGroups = Array.prototype.slice.call(arguments);
  restGroups.splice(0,2);
  if(!restGroups.length) {
    return currGrouping;
  }
  return _.transform(currGrouping, function(result, value, key) {
    result[key] = multiGroupBy.apply(null, [value].concat(restGroups));
  }, {});
}
console.log(multiGroupBy([{x:1,y:1,z:1},{x:1,y:2,z:1},{x:2,y:1,z:1},{x:2,y:2,z:1},{x:1,y:1,z:2},{x:1,y:2,z:2},{x:2,y:1,z:2},{x:2,y:2,z:2}],'x','y'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

对于那些你正在寻找类似的所有者,但没有布尔值作为过滤器的第一个属性,你可以做一个双groupby:

export function groupByLodash(results: myType[]) {
  return mapValues(
    groupBy(results, 'property.to.group'),
    (result: myType) => groupBy(result, 'second.property.to.group'),
  );
}

的结果应该类似于:

{
"property.to.group": { "second.property.to.group": {...result}}
}

在纯JS上对没有LODASH的对象或数组进行分组和过滤:

// Группировка и фильтрация объекта или массива без LODASH на чистом JS:
let k = "HUID", // group by; 
input = [
{HUID:11,test:1},
{HUID:11,test:111},
{HUID:'eeeeeeeeeeee',test:11111},
{HUID:22,test:2},
{HUID:33,test:3}
],
result = input.reduce((map, obj) => { 
//if(!obj.selected) { return map; } 
let makeCode = (map[obj[k]] = map[obj[k]] || {}); // var modelCode = makeCode[obj.HUID] = makeCode[obj.HUID] || { count: 0 }; 
let l = map[obj[k]],
    m = Object.keys(l).length; 
l[m] = { ...obj }; 
return map; 
}, {} );
console.log(result);

从VK复制

您不需要重复所有数组对象。使用loadash,您可以像下面这样做:

_.mapValues(_.groupBy(object, 'yourKeys'))