3

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.

apsillers
  • 112,806
  • 17
  • 235
  • 239
chasez0r
  • 544
  • 5
  • 18
  • 2
    Please read [ask]. Key phrases: "Search, and research" and "Explain ... any difficulties that have prevented you from solving it yourself". – Heretic Monkey Feb 10 '17 at 18:45
  • 2
    You haven't asked a question. – Felix Kling Feb 10 '17 at 18:45
  • Updated question. – chasez0r Feb 10 '17 at 18:48
  • do you have tried something? what happens with `7`? – Nina Scholz Feb 10 '17 at 18:49
  • Nothing working yet. Don't think about this as a list of integers, they could be strings. Given the working array, I am trying to find the intersections / overlap that exists. 7 should be irrelevant. – chasez0r Feb 10 '17 at 18:52
  • Not sure what "intersections" means? What is the algorithm used to derive expected result from input? – guest271314 Feb 10 '17 at 18:53
  • 1
    @guest271314 What the OP wants is "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." 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. – apsillers Feb 10 '17 at 18:56
  • @apsillers Yes exactly. – chasez0r Feb 10 '17 at 19:01
  • 1
    basically a duplicate of [Find connected components in a graph](http://stackoverflow.com/questions/21078445/find-connected-components-in-a-graph) but specifically for JavaScript code – apsillers Feb 10 '17 at 19:26

4 Answers4

2

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]
]
Community
  • 1
  • 1
chasez0r
  • 544
  • 5
  • 18
1

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)))
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • I guess you are calculating the disjointed unions however it might not be what's requested. For example in your second example the edge with the vertices `"4:5"` is not connected with any of the edges with vertices `"0:3"`, `"1:3"` and `"3:6"` yet listed in the same array. – Redu Feb 11 '17 at 12:29
0

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; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
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);
Redu
  • 25,060
  • 6
  • 56
  • 76