如何在数组数组中查找并提取所有重复的子集?

时间:2016-09-09 08:00:47

标签: javascript arrays algorithm

我有这个数组包含两个子集7,8和1两次:

[
  [1,2],
  [9,10,7,8],
  [5,6,7,8],
  [1]
]

如何在此数组中找到并提取所有子集(包含多次,即不是自身)并得到以下结果?

[
  [2],
  [9,10],
  [7,8],
  [5,6],
  [1]
]

子集总是连续的,即9,7不应被视为9,10,7,8的子集。

修改 最终数组的顺序无关紧要,但项目应该与起始数组相似:

  ok=[               ok=[            notOk=[
      [2],               [9,10],            [10,9],
      [9,10],            [2],               [2],
      [7,8],             [5,6],             [6,5],
      [5,6],             [1],               [1],
      [1]                [7,8]              [8,7]
    ]                  ]                   ]

非常感谢任何非递归解决方案。

2 个答案:

答案 0 :(得分:1)

您可以使用地图作为常用项目。从地图中删除具有单个计数的项目,使用地图首先构建公共结果集。然后在检查是否常见后使用其余的结果集,然后返回或检查是否连续,追加到最后的结果集,或者将新数组添加到结果集。



var data = [[1, 2], [9, 10, 7, 8], [5, 6, 7, 8], [1]],
    result = [],
    common = new Map;

// get all items and store the occurence
data.forEach((a, i) => a.forEach(b => {
    if (!common.has(b)) {
        common.set(b, []);
    }
    common.get(b).push(i);
}));

// keep only occurence of more then one
common.forEach((v, k, m) => v.length === 1 && m.delete(k));

// get common keys, sort and push single or contiguous elements to the result set
[...common.keys()].sort((a, b) => a - b).forEach((k, i, kk) => {
    var l = kk[i - 1];
    if (l === k - 1 && common.get(l).toString() === common.get(k).toString()) {
        result[result.length - 1].push(k);
        return;
    }
    result.push([k]);
});

// push non common items to the result set
data.forEach((a, i) => a.forEach(function (b, i, bb) {
    var l = bb[i - 1];
    if (common.has(b)) {
        return;
    }
    if (!common.has(l) && l === b - 1) {
        result[result.length - 1].push(b);
        return;
    }
    result.push([b]);
}));

console.log(result);

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




答案 1 :(得分:1)

我建议这个解决方案为每个不同的值构建一个map(哈希),为它提供一系列的出现。每个这样的数组元素提供发生值的子数组(来自输入),以及它在该子数组中的索引。

在第二步中,比较等值元素的后继者。如果那些也是相同的,并且该值不会出现在任何其他地方(即具有不同的前任),那么可以得出结论,后继值应该与前面的值保持连接。当这种情况发生时,接下来的后继者将接受测试,看看是否可以形成一个完整的三元组,等等。

在下面的代码中,我使用了与问题中提供的输入数据不同的输入数据,因为与其他解决方案(我之前发布的)相比,此解决方案产生的输出数据不同。

代码使用ES6语法:



var input = [
  [1,3],
  [9,11,7,12,2],
  [5,0,7,12,2,8,10,7,12,2],
  [1]
];

// build hash (map)
var hash = input.reduce ( (hash, arr) => 
    arr.reduce ( (hash, val, index) => 
        // Collect the array element's references in a Map keyed by value: 
        hash.set(val, (hash.get(val) || []).concat({ arr, index })),
        hash 
    ), new Map() // initial value of the hash is an empty Map
);

var result = Array.from(hash, ([val, matches]) => {
    var match = matches[0];
    // Compare the sucessors of the elements that are equal
    for (var offset = 1; match.index + offset < match.arr.length; offset++) {
        var valAtOffset = match.arr[match.index+offset];
        // If the sucessor values only occur as successor of the preceding value, 
        // and all these successors have the same value, then keep this value together
        // with the preceding value:
        if (hash.get(valAtOffset).length !== matches.length ||
            matches.some( match => match.arr[match.index+offset] !== valAtOffset )) break;
        // Remove the hash entry for the value that is now part of this unbroken sequence
        hash.delete(valAtOffset);
    }
    return match.arr.slice(match.index, match.index+offset);
});

// output:
console.log(JSON.stringify(result));
&#13;
&#13;
&#13;