在javascript中对数组中的重复数组进行计数

counting duplicate arrays within an array in javascript

本文关键字:数组 javascript      更新时间:2023-09-26

我有一个数组的数组,如下所示:

    [[3, 4], [1, 2], [3, 4]]

我想创建一个包含数组的新数组,该数组没有重复项,并且对第一个数组中每个元素的出现次数进行计数:

    [[3,4,2], [1,2,1]]

到目前为止是这样的:

var alreadyAdded = 0; 
dataset.forEach(function(data) {
 From = data[0];
 To = data[1];
 index = 0;
 newDataSet.forEach(function(newdata) {
  newFrom = newData[0];
  newTo = newData[1];
  // check if the point we are looking for is already added to the new array
  if ((From == newFrom) && (To == newTo)) {
   // if it is, increment the count for that pair
   var count = newData[2];
   var newCount = count + 1;
   newDataSet[index] = [newFrom, newTo, newCount];
   test = "reached here";
   alreadyAdded = 1;
  }
  index++;
 });
 // the pair was not already added to the new dataset, add it
 if (alreadyAdded == 0) {
  newDataSet.push([From, To, 1]);
 }
 // reset alreadyAdded variable
 alreadyAdded = 0;
});

我是非常新的Javascript,有人可以帮助解释给我我做错了什么?我相信有一个更简洁的方法来做到这一点,但是我没能在javascript中找到一个例子来处理数组的重复数组。

根据你要迭代的数据集的大小,我会谨慎地循环这么多次。您可以通过为原始数据集中的每个元素创建一个"索引",然后使用它来引用分组中的元素来避免这样做。这是我解决这个问题时所采用的方法。你可以在youtube上看到。我使用Array.prototype.reduce来创建一个对象字面值,其中包含来自原始数据集的元素分组。然后我迭代它的键来创建最终的分组。

var dataSet = [[3,4], [1,2], [3,4]],
    grouping = [],
    counts,
    keys,
    current;
counts = dataSet.reduce(function(acc, elem) {
    var key = elem[0] + ':' + elem[1];
    if (!acc.hasOwnProperty(key)) {
        acc[key] = {elem: elem, count: 0}
    }
    acc[key].count += 1;
    return acc;
}, {});
keys = Object.keys(counts);
for (var i = 0, l = keys.length; i < l; i++) {
    current = counts[keys[i]];
    current.elem.push(current.count);
    grouping.push(current.elem);
}
console.log(grouping);

假设子数组项的顺序很重要,假设子数组可以是可变长度的,并且可以包含数字以外的项,这里有一个相当通用的方法来解决这个问题。目前需要与ECMA5兼容,但在ECMA3上工作并不难。

Javascript

// Create shortcuts for prototype methods
var toClass = Object.prototype.toString.call.bind(Object.prototype.toString),
    aSlice = Array.prototype.slice.call.bind(Array.prototype.slice);
// A generic deepEqual defined by commonjs
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
function deepEqual(a, b) {
    if (a === b) {
        return true;
    }
    if (toClass(a) === '[object Date]' && toClass(b) === '[object Date]') {
        return a.getTime() === b.getTime();
    }
    if (toClass(a) === '[object RegExp]' && toClass(b) === '[object RegExp]') {
        return a.toString() === b.toString();
    }
    if (a && typeof a !== 'object' && b && typeof b !== 'object') {
        return a == b;
    }
    if (a.prototype !== b.prototype) {
        return false;
    }
    if (toClass(a) === '[object Arguments]') {
        if (toClass(b) !== '[object Arguments]') {
            return false;
        }
        return deepEqual(aSlice(a), aSlice(b));
    }
    var ka,
        kb,
        length,
        index,
        it;
    try {
        ka = Object.keys(a);
        kb = Object.keys(b);
    } catch (eDE) {
        return false;
    }
    length = ka.length;
    if (length !== kb.length) {
        if (Array.isArray(a) && Array.isArray(b)) {
            if (a.length !== b.length) {
                return false;
            }
        } else {
            return false;
        }
    } else {
        ka.sort();
        kb.sort();
        for (index = 0; index < length; index += 1) {
            if (ka[index] !== kb[index]) {
                return false;
            }
        }
    }
    for (index = 0; index < length; index += 1) {
        it = ka[index];
        if (!deepEqual(a[it], b[it])) {
            return false;
        }
    }
    return true;
};
// Recursive function for counting arrays as specified
// a must be an array of arrays
// dupsArray is used to keep count when recursing
function countDups(a, dupsArray) {
    dupsArray = Array.isArray(dupsArray) ? dupsArray : [];
    var copy,
        current,
        count;
    if (a.length) {
        copy = a.slice();
        current = copy.pop();
        count = 1;
        copy = copy.filter(function (item) {
            var isEqual = deepEqual(current, item);
            if (isEqual) {
                count += 1;
            }
            return !isEqual;
        });
        current.push(count);
        dupsArray.push(current);
        if (copy.length) {
            countDups(copy, dupsArray);
        }
    }
    return dupsArray;
}
var x = [
    [3, 4],
    [1, 2],
    [3, 4]
];
console.log(JSON.stringify(countDups(x)));

输出
[[3,4,2],[1,2,1]] 
在jsFiddle

修复错别字后,我在调试器中尝试了您的解决方案;它的工作原理!

修正了内部foreach循环变量名称以匹配大小写。还添加了一些var关键字。

  var alreadyAdded = 0;
  dataset.forEach(function (data) {
    var From = data[0];
    var To = data[1];
    var index = 0;
    newDataSet.forEach(function (newData) {
        var newFrom = newData[0];
        var newTo = newData[1];
        // check if the point we are looking for is already added to the new array
        if ((From == newFrom) && (To == newTo)) {
            // if it is, increment the count for that pair
            var count = newData[2];
            var newCount = count + 1;
            newDataSet[index] = [newFrom, newTo, newCount];
            test = "reached here";
            alreadyAdded = 1;
        }
        index++;
    });
    // the pair was not already added to the new dataset, add it
    if (alreadyAdded == 0) {
        newDataSet.push([From, To, 1]);
    }
    // reset alreadyAdded variable
    alreadyAdded = 0;
});

const x = [[3, 4], [1, 2], [3, 4]];
const with_duplicate_count = [
  ...x
    .map(JSON.stringify)
    .reduce( (acc, v) => acc.set(v, (acc.get(v) || 0) + 1), new Map() )
    .entries()
].map(([k, v]) => JSON.parse(k).concat(v));
console.log(with_duplicate_count);