JavaScript对数组中的项进行排序和分组

时间:2017-07-31 07:54:29

标签: javascript arrays sorting grouping

我正在尝试在JavaScript中进行一些映射。我想要做的是尝试检查arrdatasetarr的类型是否存在,如果存在,我会在datasetarr中获取索引并增加该索引的数量。如果不存在,我在datasetarr中添加一个新条目。这是我的代码:

var datasetarr = [];
var pos;
for(var i = 0; i < arr.length; i++){
    console.log('unsorted ' + arr[i].type + ' ' + arr[i].quantity);
    if(datasetarr.indexOf(arr[i].type) > -1){
        pos = datasetarr.indexOf(arr[i].type);
        datasetarr[pos].quantity += arr[i].quantity;
    }else{
        datasetarr.push({type: arr[i].type, quantity: arr[i].quantity});
    }
}

for(var i = 0; i < datasetarr.length; i++){
    console.log('sorted ' + datasetarr[i].type + ' ' + datasetarr[i].quantity);
}

输出应为:

kitchen appliance 20
home entertainment 8
batteries & lightings 4
home appliance 12

然后,我可以得到每种类型和数量并存储到数组中供我绘制图表。

但是,根据我上面的代码,我得到的东西与未分类的东西完全相同。我逻辑的哪些部分出错了?

5 个答案:

答案 0 :(得分:2)

使用对象进行分组。

var categories = {};

function incrementBy(category, value) {
  if (!categories[category]) {
    categories[category] = 0;
  }
  categories[category] += value;
}

var datasetarr = [];
var pos;
for(var i = 0; i < arr.length; i++){
  console.log('unsorted ' + arr[i].type + ' ' + arr[i].quantity);
  incrementBy(arr[i].type, arr[i].quantity)
}

for(var category in categories){
  console.log('sorted ' + category + ' ' + categories[category]);
}

如果需要,您可以将对象分解为数组,并在需要时对其进行排序。

一个更清洁的例子,可能会让你更好地跟随一点:

var arr = [{type: 'kitchen appliance', quantity: 2},
    {type: 'home entertainment', quantity: 2},
    {type: 'home entertainment', quantity: 3},
    {type: 'batteries & lightings', quantity: 2},
    {type: 'home entertainment', quantity: 2},
    {type: 'home appliance', quantity: 5},
    {type: 'kitchen appliance', quantity: 4},
    {type: 'kitchen appliance', quantity: 5},
    {type: 'kitchen appliance', quantity: 3},
    {type: 'kitchen appliance', quantity: 4},
    {type: 'kitchen appliance', quantity: 1},
    {type: 'home entertainment', quantity: 1},
    {type: 'home appliance', quantity: 5},
    {type: 'batteries & lightings', quantity: 2},
    {type: 'kitchen appliance', quantity: 2},
    {type: 'home appliance', quantity: 2}];


function group(array) {
    var categories = {};

    function incrementBy(category, value) {
        if (!categories[category]) {
            categories[category] = 0;
        }
        categories[category] += value;
    }

    array.forEach(function (value, index, arr) {
        incrementBy(value.type, value.quantity)
    });

    return categories;
}

function print(categories) {
    for (var category in categories) {
        console.log('%s: %s', category, categories[category]);
    }
}

print(group(arr));

这里有group隐藏分组的解决方案,它可以保存您自己的实现:

function group(array) {
    var categories = {};

    function incrementBy(object) {
        var category = categories[object.type];
        if (!category) {
            category = categories[object.type] = {};
        }
        var subCategory = category[object.subType];
        if (!subCategory) {
            subCategory = category[object.subType] = {};
        }
        subCategory += object.value;
    }

    array.forEach(function (value, index, arr) {
        incrementBy(value, value.quantity)
    });

    return categories;
}

根据您的使用情况,您还可以展平结构:

function incrementBy(object) {
    var key = [object.type, object.subType].join('/');
    var category = categories[key];
    if (!category) {
        category = categories[key] = {};
    }
    subCategory += object.value;
}

但是有各种各样的地图可能有意义:

function groupings(array) {
    var groupings = {
      types: {},
      subTypes: {},
      paths: {}
    };

    function incrementBy(object) {
        var category = groupings['types'][object.type];
        if (!category) {
            category = groupings['types'][object.type] = {};
        }
        category += object.value;

        var subCategory = groupings['subTypes'][object.subType];
        if (!subCategory) {
            subCategory = groupings['subTypes'][object.subType] = {};
        }
        subCategory += object.value;


        var key = [object.type, object.subType].join('/');
        var path = groupings['paths'][key];
        if (!path) {
            path = groupings['paths'][key] = {};
        }
        path += object.value;
    }

    array.forEach(function (value, index, arr) {
        incrementBy(value, value.quantity)
    });

    return categories;
}

为避免聚合上的信息丢失,您可以简单地创建更复杂的数据结构:

function groupByAndSumBy(data, groupByProperty, sumByProperty) {
  var accumulator = {};

  data.forEach(function(object, index, array) {
      var localAcc = accumulator[groupByProperty]
            = accumulator[groupByProperty] || { items: [] };
      localAcc[sumByProperty]
            = (localAcc[sumByProperty] || 0) + object[sumByProperty];
      localAcc.items.push(object);
  });

  return accumulator;
}

function groupByMerchantNameAndSumByTotalSales(data) {
    return groupByAndSumBy(data, 'merchantName', 'totalSales');
}

这将创建一个聚合,该聚合还包含输入数组的子集,从而可以更详细地查看数据。

答案 1 :(得分:2)

一般情况下,我建议lodash使用这种东西

result = _(arr)
    .groupBy('type')
    .mapValues(xs => _.sumBy(xs, 'quantity'))
    .value();

然而,在这种特殊情况下,一个普通的JS解决方案同样容易:

let result = {};

for (let item of arr)
    result[item.type] = (result[item.type] || 0) + item.quantity;

答案 2 :(得分:0)

这是因为,你的If条件只检查结果数组 datasetarr 中的索引值,该数组已经为空,以便推送下一个值,

所以你的

        if(datasetarr.indexOf(arr[i].type) > -1){
        pos = datasetarr.indexOf(arr[i].type);
        datasetarr[pos].quantity += arr[i].quantity;
    }

永远不会执行。 这就是你获得与输入相同的输出的原因。

答案 3 :(得分:0)

您可以编写这样的通用聚合函数,并通过指定分类和聚合的键(分别为<my-dialog> <p>this content will appear in the dialog</p> </my-dialog> type)来调用它。最后,您指定quantity函数,它只是一个总和,reducer

a + b

答案 4 :(得分:-1)

基于OP问题:

  

我试着检查来自arr的类型是否存在于datasetarr中,如果存在,我在datasetarr中获取索引并增加该索引的数量。如果不存在,我在datasetarr中添加一个新条目。

评论中的澄清:

  

问:所以基本上你想按类型和总和数量值对数组进行分组? (并在datasetarr中输出结果)
  答:是的,这就是我想要实现的目标。

我认为最好和最简单的方法是做到这一点,检查是否存在并采取相应的行动。

var datasetarr = [];
for (var i = arr.length - 1; i >= 0; i--) {
  if (datasetarr.hasOwnProperty(arr[i]["type"])) {
    // exist -> increment
    datasetarr[arr[i]["type"]] = datasetarr[arr[i]["type"]] + arr[i]["quantity"];
  } else {
    // no exist -> add new
    datasetarr[arr[i]["type"]] = arr[i]["quantity"];
  }
}

datasetarr变量的预期输出为:

datasetarr = {
    "batteries & lightings" => 4,
    "home appliance" => 12,
    "home entertainment" => 8,
    "kitchen appliance" => 21
];