简体   繁体   中英

Javascript group array by intersection

Given an array of paired integers, HOW can I group by intersections. Does anyone have a simple function that could convert my input, into the desired output?

Input

var in = ["0:3", "1:3", "4:5", "5:6", "6:8"]

Desired output

[
    [0, 1, 3],
    [4, 5, 6, 8]
]

UPDATE:

@apsiller asked my question in the comments more clearly then I originally posted:

"Considering each number as a node in a graph, and each pairing x:y as an edge between nodes x and y , find the sets of numbers that can be traveled to using the edges defined. That is, in graph theory terms, find the distinct connected components within such a graph.

For instance, there is no way to travel from 4 to 0 so they are in different groups, but there is a way to travel from 1 to 0 (by way of 3) so they are in the same group."

To reiterate the desired output is a grouping of transversable nodes, based on a potentially random input set.

You could do something like this.

 function group(data) { var r = [[]],c = 0,a = [0] var d = data.map(e => e.split(':').sort((a, b) => a - b)).sort((a, b) => a[0] - b[0]) d.forEach(function(e, i) { if (e[0] > a[a.length - 1]) { r.push(e) a.push(e[1]) c++ } else { r[c] = r[c].concat(e) a[a.length - 1] = e[1] } }) return r.map(e => [...new Set(e)].sort((a, b) => a - b)) } var test1 = ["0:3", "1:3", "4:5", "5:6", "6:8"] var test2 = ["0:3", "1:3", "4:5", "9:11", "10:12", '3:6', "7:8"] var test3 = ["20:15", "4:0", "1:3", "5:1", "9:11", "10:12", '3:6', "8:7"] console.log(JSON.stringify(group(test1))) console.log(JSON.stringify(group(test2))) console.log(JSON.stringify(group(test3))) 

Thanks everyone. Given everyones input I was able to find a similar question on here that led me my answer. Finding All Connected Components of an Undirected Graph

The first step was to change my input to groups of pairs.

var input = [
    [0, 3],
    [1, 3],
    [4, 5],
    [5, 6],
    [6, 8]
]

The next step was to use whats called Breadth-first search

function breadthFirstSearch(node, nodes, visited) {
    var queue = [];
    var group = [];
    var pair  = null;
    queue.push(node);
    while (queue.length > 0) {
        node = queue.shift();
        if (!visited[node]) {
            visited[node] = true;
            group.push(node);
            for (var i = 0, len = nodes.length; i < len; i++) {
                pair = nodes[i];
                if (pair[0] === node && !visited[pair[1]]) {
                    queue.push(pair[1]);
                } else if (pair[1] === node && !visited[pair[0]]) {
                    queue.push(pair[0]);
                }
            }
        }
    }
    return group;
};

function groupReachableVertices(input) {
    var groups  = [];
    var visited = {};
    for (var i = 0, len = input.length; i < len; i += 1) {
        var current_pair = input[i];
        var u = current_pair[0];
        var v = current_pair[1];
        var src = null;
        if (!visited[u]) {
            src = u;
        } else if (!visited[v]) {
            src = v;
        }
        if (src) {
            groups.push(breadthFirstSearch(src, input, visited));
        }
    }
    return groups;
};

Putting it all together...

var output = groupReachableVertices(input);
[
    [0, 1, 3],
    [4, 5, 6, 8]
]

You could use a hash table and collect all nodes in it. It works for any values.

 var data = ["0:3", "1:3", "4:5", "a:8", "5:a"], result = data .map(function (a) { return a.split(':'); }) .reduce(function (hash) { return function (r, a) { if (hash[a[0]] && hash[a[1]]) { hash[a[0]].push.apply(hash[a[0]], r.splice(r.indexOf(hash[a[1]]), 1)[0]); hash[a[1]] = hash[a[0]]; return r; } if (hash[a[0]]) { hash[a[1]] = hash[a[0]]; hash[a[1]].push(a[1]); return r; } if (hash[a[1]]) { hash[a[0]] = hash[a[1]]; hash[a[0]].push(a[0]); return r; } hash[a[0]] = a.slice(); hash[a[1]] = hash[a[0]]; return r.concat([hash[a[0]]]); }; }(Object.create(null)), []); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

I guess, by using Object.values() and Set object you can simply do as follows in ES6.

 function getConnectedVertices(a){ return [...new Set(Object.values(a.reduce((h,v) => (h[v[0]] ? h[v[1]] ? (h[v[0]] = h[v[0]].concat(h[v[1]]), h[v[1]] = h[v[0]]) : (h[v[0]].push(v[1]), h[v[1]] = h[v[0]]) : h[v[1]] ? (h[v[1]].push(v[0]), h[v[0]] = h[v[1]]) : h[v[0]] = h[v[1]] = v, h),{})))]; } var input = ["0:3", "1:3", "4:5", "5:6", "6:8"].map(s => s.split(":")), result = getConnectedVertices(input); console.log(result); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM