Getting the lengthiest path in an array, functional style - javascript

I have an array of SVG lines that represent the sides of a triangle, I want to color the lengthiest one (the hypotenuse). Assuming ab, bc and ca are the the SVG line elements...
var hypotenuse = [ab, bc, ca].sort(getLineLength)[0];
hypotenuse.setAttribute("stroke-width", 5);
function getLineLength(el) {
var x1 = el.getAttribute("x1");
var x2 = el.getAttribute("x2");
var y1 = el.getAttribute("y1");
var y2 = el.getAttribute("y2");
var xs = x2 - x1;
var ys = y2 - y1;
xs = xs * xs;
ys = ys * ys;
return Math.sqrt(xs + ys);
}​
This doesn't work, it seems it grabs the first element always. It also doesn't look very intuitive. What is the correct way to achieve this in Javascript? I know how to do it in loops but I'd like to know if there's some functional idiom that allows me to achieve this.
JSFiddle is here: http://jsfiddle.net/btbkd/

Because function in array.sort(function) expects two arguments, and you should return an Integer which is
less than zero (indicates that the first one should be prior than the second one);
zero (indicates that the two is equal);
larger than zero (indicates that the second one is prior than the first one).
MDN Document
Also you forgot to reset the line width.
JSFiddle
Edit:
Noted that I get rid of the Math.sqrt part from your getLineLength function, because if comparing is all that you expect from this function, calculating square root is not necessary, and removing it may make it a little bit faster.

When you pass a function to sort(), that function has to take two arguments and return the result of comparing them (-1, 0, or 1), or if comparing numbers then you can just subtract the two arguments: Mozilla Array.sort Reference
A simple way to make your example work should be something like this:
var hypotenuse = [ab, bc, ca].sort(function(lineOne, lineTwo) {
return getLineLength(lineTwo) - getLineLength(lineOne);
})[0];
And then the rest like you already have. Note that the order of the subtraction is important, as it will be the difference between sorting from lowest to highest or from highest to lowest.

I don't remember JavaScript syntax, so the syntax may be wrong, but if I understand your question correctly no sort() should be necessary and you should be able to do:
var maxLength = 0;
var longestElement = -1;
for (var i = 0; i < array.length; i++) {
if( getLineLength(array[i]) > maxLength )
longestElement = i;
}
If longestElement is -1, there is no line with a length greater than 0. Otherwise, hypotenuse is array[longestElement].
Note that neither this nor the sort() example does any special handling for lines of equal length (e.g. an equilateral triangle).

Related

how to discriminate two numbers that are very near?

So my case goes like this, my software that is being develop on JavaScript needs to manipulate exact numeric values but sometimes it can happen that the values are way too near and I need to discriminate.
This is a case example:
0:(2) [112.02598008561951, 9.12963236661007]
1:(2) [112.02598008561952, 9.129632366610064]
2:(2) [9.751846481442218, 3.5376744911193576]
In this array position 0 and 1 has similar values but with an slight difference at the end of the decimals, but the one that counts is the position 0, because the two numbers are way near it messes with the process that follows next.
So, how do I do to discriminate near numbers and just use the first of the similar numbers given?
In the end the end result would be an array like this:
0:(2) [112.02598008561951, 9.12963236661007]
1:(2) [9.751846481442218, 3.5376744911193576]
I tried doing a truncation but I need the whole number to work with.
Edit: as one of the comments asked about if the points can vary or not, in my real problem I get a series of numbers that I sort normally I get like 3 points or best case scenario I get 2 points.
Sometimes this problem happens when I get near numbers and the first layer of sorting doesn't work as intended and the next part doesn't work well.
In short, you need to consider that it is always like 3 positions of coordinates.
In short your easiest option is to round to a fixed number of decimal places. This is because floats in JS (and in computer science in general) can be a tricky thing. For example, this should make you want to throw your computer:
var x = 0.1 * 0.2; //-> 0.020000000000000004
There are different use cases for needing super exact precision (eg. when dealing with money, trajectory of a satellite, etc), but most use cases only need "good enough" precision. In your case, it's best to round all of your numbers to a fixed decimal length so that you don't encounter the low-level inaccuracies.
var ACCURACY = 100000000;
var round= (num) => Math.round(num * ACCURACY) / ACCURACY;
var x = round(0.1 * 0.2); //-> 0.2
If you trust the numbers you have and you're just needing to filter out a pair which is close to another pair, you will need to write a little function to apply your heuristics.
var areClose = (x, y) => Math.abs(x - y) < 0.0000000001;
var filterPoints = (arr) => {
return arr.filter(([x, y], i) => {
for(var n = i - 1; n >= 0; n--) {
if (areClose(x, arr[n][0]) && areClose(y, arr[n][1])) {
return false;
}
}
return true;
});
}
filterPoints([
[112.02598008561951, 9.12963236661007],
[112.02598008561952, 9.129632366610064],
[9.751846481442218, 3.5376744911193576],
]);
// [
// [112.02598008561951, 9.12963236661007],
// [9.751846481442218, 3.5376744911193576]]
// ]
Note: this will keep the "first" set of values. If you wish to keep the "last" set, then you can flip the inner loop to crawl upwards:
for(var n = i + 1; n < arr.length; n++) { ...
Let's see if I understood correctly, you have this array with vertex points, usually it's just a 2 elements bidimensional array, but sometimes it might receive an extra vertex points array, with a slight different value (differ of 1*10^-14) and you want to discard the higher extra values.
I came up with something like this:
const arr = [
[112.02598008561951, 9.12963236661007],
[112.02598008561952, 9.129632366610064],
[9.751846481442218, 3.5376744911193576],
];
for (let i = 0; i < arr.length-1; i++) {
const diff = Math.abs(arr[i][0] - arr[i + 1][0])
if (diff <= 0.00000000000002) arr.splice(i + 1, 1);
}
console.log("NEW ARR", arr)
This just checks the first element of the array, since if I understood correctly it automatically means even the second element differs of a similar amount.
I'm using a (2*10-14) threshold since 1 is not enough, not sure if it's due to JS issues with float precision.
You could sort and reduce
let arr = [
[112.02598008561952, 9.129632366610064],
[112.02598008561951, 9.12963236661007],
[9.751846481442218, 3.5376744911193576]
]
arr.sort((a,b) => a[0]-b[0]); // swap a and b for descending
const precision = 0.00000000000002;
arr = arr.reduce((acc,cur,i) => {
if (i===0) { acc.push(cur); return acc}
const diff = Math.abs(acc[acc.length-1][0]-cur[0])
if (diff > precision) acc.push(cur)
return acc
},[])
console.log(arr)
What about something like
const removeDecimalPlaces = (num) => Math.floor(num * 10000000000000) / 10000000000000;
console.log(removeDecimalPlaces(112.02598008561951) === removeDecimalPlaces(112.02598008561952))

Neural Network, gradient descent only finds the average of the outputs?

This problem is more conceptual than in the code, so the fact that this is written in JS shouldn't matter very much.
So I'm trying to make a Neural Network and I'm testing it by trying to train it to do a simple task - an OR gate (or, really, just any logic gate). I'm using Gradient Descent without any batches for the sake of simplicity (batches seem unnecessary for this task, and the less unnecessary code I have the easier it is to debug).
However, after many iterations the output always converges to the average of the outputs. For example, given this training set:
[0,0] = 0
[0,1] = 1
[1,0] = 1
[1,1] = 0
The outputs, no matter the inputs, always converge around 0.5. If the training set is:
[0,0] = 0,
[0,1] = 1,
[1,0] = 1,
[1,1] = 1
The outputs always converge around 0.75 - the average of all the training outputs. This appears to be true for all combinations of outputs.
It seems like this is happening because whenever it's given something with an output of 0, it changes the weights to get closer to that, and whenever it's given something with an output of 1, it changes the weights to get closer to that, meaning that overtime it will converge around the average.
Here's the backpropagation code (written in Javascript):
this.backpropigate = function(data){
//Sets the inputs
for(var i = 0; i < this.layers[0].length; i ++){
if(i < data[0].length){
this.layers[0][i].output = data[0][i];
}
else{
this.layers[0][i].output = 0;
}
}
this.feedForward(); //Rerun through the NN with the new set outputs
for(var i = this.layers.length-1; i >= 1; i --){
for(var j = 0; j < this.layers[i].length; j ++){
var ref = this.layers[i][j];
//Calculate the gradients for each Neuron
if(i == this.layers.length-1){ //Output layer neurons
var error = ref.output - data[1][j]; //Error
ref.gradient = error * ref.output * (1 - ref.output);
}
else{ //Hidden layer neurons
var gradSum = 0; //Find sum from the next layer
for(var m = 0; m < this.layers[i+1].length; m ++){
var ref2 = this.layers[i+1][m];
gradSum += (ref2.gradient * ref2.weights[j]);
}
ref.gradient = gradSum * ref.output * (1-ref.output);
}
//Update each of the weights based off of the gradient
for(var m = 0; m < ref.weights.length; m ++){
//Find the corresponding neuron in the previous layer
var ref2 = this.layers[i-1][m];
ref.weights[m] -= LEARNING_RATE*ref2.output*ref.gradient;
}
}
}
this.feedForward();
};
Here, the NN is in a structure where each Neuron is an object with inputs, weights, and an output which is calculated based on the inputs/weights, and the Neurons are stored in a 2D 'layers' array where the x dimension is the layer (so, the first layer is the inputs, second hidden, etc.) and the y dimension is a list of the Neuron objects inside of that layer. The 'data' inputted is given in the form [data,correct-output] so like [[0,1],[1]].
Also my LEARNING_RATE is 1 and my hidden layer has 2 Neurons.
I feel like there must be some conceptual issue with my backpropagation method, as I've tested out the other parts of my code (like the feedForward part) and it works fine. I tried to use various sources, though I mostly relied on the wikipedia article on backpropagation and the equations that it gave me.
.
.
I know it may be confusing to read my code, though I tried to make it as simple to understand as possible, but any help would be greatly appreciated.

Array sort algorithm on two values. One descending other ascending. Javascript

I have the following array structure in Javascript:
var unsorted = [
{h:50,t:70},
{h:70,t:60},
{h:30,t:10}, // Ideal Value (Best combination of t being the least and h being the highest )
{h:10,t:30},
{h:2,t:10}
]
I need to sort it in a way that the value "{h:30,t:10}" colud be on top or at last in the array.
I tried bubble sort but I dont know how I should make it work with two values.
Bubble Sort:
function bubbleSort(a){
var swapped;
do{
swapped=false;
for(var i=0;i<a.length-1;i++){
var firstValue = parseInt(a[i].h) ;
var secondValue = parseInt(a[i+1].h) ;
if( firstValue > secondValue ){
var temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
swapped=true;
}
}
} while(swapped);
return a;
}
Any other way than the bubble sort is ok.
You can use the javascript builtin sort function.
Here's the code where sorted is your new sorted array:
var sorted = unsorted.sort(function(a,b) {
return (a.t-b.t) * 1000 + (b.h-a.h);
});
Note that this assumes your numbers in h will not be bigger than 999, or otherwise you will have to increase the multiplier of 1000 to something bigger.
Here's the reference to the javascript sort function: http://www.w3schools.com/jsref/jsref_sort.asp
A better way of doing this would be
var sorted = unsorted.sort(function(a, b) {
return a.t === b.t ? b.h - a.h : a.t - b.t;
});
This way it works for any size of t or h. (Also fails gracefully for NaN and Infinity).

Finding minimal distance between unsorted and sorted lists

Let A be a list and S a sorted list of the same elements. Assume all elements are different. How do I find a minimal set of "moves" (move X before Y (or end)) that turns A into S?
Examples:
A = [8,1,2,3]
S = [1,2,3,8]
A => S requires one move:
move 8 before end
A = [9,1,2,3,0]
S = [0,1,2,3,9]
A => S requires two moves:
move 9 before 0
move 0 before 1
I prefer javascript or python, but any language will do.
This problem is equivalent to longest increasing subsequence problem.
You will have to define a comparison operator less. less(a, b) will return true if and only if a is before b in the target sequence. Now using this comparison operator, compute the maximum increasing sub sequence of the source sequence. You will have to move each element that is not part of this sub sequence (otherwise the sub sequence will not be maximum) and you can move it exactly once(moving it to its target position).
EDIT: As requested by amit here is my proof to the statement above:
Lets we denote the target sequence B and lets denote the source sequence A. Let n = |A| and let k be the length of the longest increasing sequence as described above.
Let's assume it is possible to reach B from A with less moves than n - k. This means that at least n - k + 1 elements from the A will not be moved. Let s1,s2,...sm be the set of elements that are not moved. From the assumption we know that m > k. Now as these elements have not moved, than their relative position with respect to each other can not have changed. Thus the relative positions of all this elements in the target sequence B is the same as the one in A. Therefor the operator less(si, sj) as defined above should be true for any i, j. But if this is true then s1,s2,...sm is increasing sequence and as m > k this leads to a contradiction with the assumption that k is the length of the longest increasing sequence.
Now lets show an algorithm to reach B from A by moving all elements but the ones that are part of the longest increasing sequence. We will move the elements in the order they appear in B. We will not move elements that are part of the longest increasing sequence. If the current element is the first one in B, we simply move it to the beginning of the sequence. Otherwise we move the current element right after the position of the previous element in B. Note that this element may either be the previous element we've moved or an element from the longest increasing sequence. Note that at each step when we are about to move element with index i, all elements with index 1, 2, ...i-1 will already be with correct relative positions with respect to each other.
EDIT: adding some code to make the answer clearer. I don't feel an expert in javascript so feel free to correct or criticize my solution.
Let's define a function transform(a, s) that takes two parameters - lists a and b as described in the statement. First I will create a map positions that maps each element in a to its position in s:
var positions = {};
for (var i = 0; i < a.length; ++i) {
positions[a[i]] = i;
}
Now that I have this array I can define a helper function less as described in my answer above. Less will take two values a and b(and the helper map I just created) and return true if and only if a is before b in s(the target list):
function less(a, b, positions) {
return positions[a] < positions[b];
}
Now I will not describe how can we find the maximum increasing subsequence in a with respect to that comparison operator. You can have a look at this question for detailed explanation how to do that. I will simply assume that I have a function defined:
function max_increasing_subsequence(a, positions)
That returns the maximum increasing subsequence in a with respect to the comparison operator less as defined above (using positions)as a list. I will use your second example to illustrate what we have so far:
A = [9,1,2,3,0]
S = [0,1,2,3,9]
The values in positions will be as follow:
positions = { 0 : 0,
1 : 1,
2 : 2,
3 : 3,
9 : 4}
And the result of max_increasing_subsequence(a, positions) will be [1, 2, 3]. By the way if there may be repeating elements in a it may be better to return indices instead of the elements from max_increasing_subsequence(in this particular example the difference will not be visible).
Now I will create another helper map to indicate which are the elements included in the maximum increasing subsequence:
var included = {};
l = max_increasing_subsequence(a, positions);
for (var i = 0; i < l.length; ++i) {
included[l[i]] = true;
}
Now you can finish up the solution with a single iteration over s. I will add a special case for the last element to make code easier to understand:
if (!(s[s.length - 1] in included)) {
console.log("Move" + s[s.length - 1] + " at the end");
}
for (var i = s.length - 2; i >= 0; --i) {
if (!(s[i] in included)) {
console.log("Move" + s[i] + " before " + s[i + 1]);
}
}
Please note that in the solution above I assume that each time you log a new command, you log it with respect to the ordering of the array a right after all previous commands have been executed.
So in total I believe transform should look something like this:
function transform(a, s) {
var positions = {};
for (var i = 0; i < a.length; ++i) {
positions[a[i]] = i;
}
var included = {};
l = max_increasing_subsequence(a, positions);
var included = {};
for (var i = 0; i < l.length; ++i) {
included[l[i]] = true;
}
if (!(s[s.length - 1] in included)) {
console.log("Move" + s[s.length - 1] + " at the end");
}
for (var i = s.length - 2; i >= 0; --i) { // note s.length - 2 - don't process last element
if (!(s[i] in included)) {
console.log("Move" + s[i] + " before " + s[i + 1]);
}
}
}
I hope this code makes my answer more clear.
If you regard your two lists as two strings -- e.g. the numbers are values in ASCII encoding -- then the problem is equivalent to that of finding the operations that allow you to transform the first string into the second one. The number of operations, in turn, is the Levenshtein or edit distance between the strings.
The Levenshtein distance can be found by using dynamic programming, storing in a matrix the distances between all prefixes of both strings, and then tracing back your steps to find at each row of the matrix which is the optimal operation (the one that has needed the least operations to arrive at it).
The longest increasing subsequence algorithm suggested by #IvayloStrandjev is related to the longest common subsequence problem, which in turn is related to the edit distance as an alternative metric that only allows insertion and substitution. Probably it is more performant in space, since it leverages the fact that one of the sequences has to be sorted; I just wanted to provide an alternative answer that I find easier to grasp.
Here is an implementation in Python of the full matrix Levenshtein algorithm, as described in the Wikipedia page linked above (originally found in a 1974 paper by Wagner and Fischer), where also a proof of correctness is supplied. Here we also store the names of the operations in a matrix of the same size as the operations scores, and we print the optimal operation after completing a row.
import argparse
import numpy as np
class Levenshtein(object):
def __init__(self, string1, string2):
self.string1 = string1
self.string2 = string2
self.scores_matrix = np.zeros(
(len(self.string1) + 1, len(self.string2) + 1), dtype=np.int16)
self.operations_matrix = np.empty_like(
self.scores_matrix, dtype=(np.str_, 16))
self.total_steps = 0
def distance(self):
m = len(self.string1) + 1
n = len(self.string2) + 1
for i in range(m):
self.scores_matrix[i, 0] = i
for j in range(n):
self.scores_matrix[0, j] = j
for j in range(1, n):
for i in range(1, m):
if self.string1[i - 1] == self.string2[j - 1]:
self.scores_matrix[i, j] = self.scores_matrix[i - 1, j - 1]
self.operations_matrix[i, j] = 'match'
else:
self.scores_matrix[i, j] = self.select_operation(i, j)
if j == n - 1: # a row is complete
self.determine_best_op_and_print(i)
return self.scores_matrix[m - 1, n - 1]
def select_operation(self, i, j):
possible_ops = ['delete', 'insert', 'substitute']
ops_scores = [
self.scores_matrix[i - 1, j] + 1, # deletion
self.scores_matrix[i, j - 1] + 1, # insertion
self.scores_matrix[i - 1, j - 1] + 1] # substitution
chosen_op = min(ops_scores)
chosen_op_name = possible_ops[ops_scores.index(chosen_op)]
self.operations_matrix[i, j] = chosen_op_name
return chosen_op
def determine_best_op_and_print(self, i):
reversed_row = self.scores_matrix[i][::-1]
reversed_pos_min = np.argmin(reversed_row)
pos_min = len(self.scores_matrix[i]) - (reversed_pos_min + 1)
best_op_name = self.operations_matrix[i, pos_min]
if best_op_name != 'match':
self.total_steps += 1
print best_op_name, self.string1[i - 1], self.string2[pos_min - 1]
def parse_cli():
parser = argparse.ArgumentParser()
parser.add_argument('--list', nargs='*', required=True)
return parser.parse_args()
if __name__ == '__main__':
args = parse_cli()
A = args.list
S = sorted(A)
lev = Levenshtein(A, S)
dist = lev.distance()
print "{} total steps were needed; edit distance is {}".format(
lev.total_steps, dist)
Here is how to run the code with the examples you provide, and the output expected:
$ python levenshtein.py --list 8 1 2 3
substitute 8 1
1 total steps were needed; edit distance is 2
$ python levenshtein.py --list 9 1 2 3 0
substitute 9 0
substitute 0 9
2 total steps were needed; edit distance is 2
This depends greatly on a few parameters of the problem that are not stated. First, what moves are legal? Neighboring-element swaps only? Any arbitrary deletions and insertions? Second, do you just need the number of moves or do you need a list of specific moves to perform? These leads to different algorithms for this:
Neighboring swaps only - This is called inversion counting, if you only care about the minimal number.
Deletions, non-neighboring swaps, etc. - Levenshtein distance, mentioned previously, is a more general edit distance. One trick about this is how you define your move-set. Is moving an element 3 places over a single move or is it two moves (a deletion and an insertion)?
Inversion counts are pretty simple and can be done with some basic recursive algorithms. You can use a merge-sort to find the inversion count between two lists by using one list to make a transformed version of the other, where the new elements are indices. So if you have two sequences, you can do:
sequence = [seq2.index(element) for element in seq]
A simple straight-Python merge-sort implementation to count the inversions is:
if len(sequence) <= 1:
return 0, sequence
else:
firstHalf = sequence[:int(len(sequence)/2)]
secondHalf = sequence[int(len(sequence)/2):]
count1, firstHalf = mergeSortInversionCount(firstHalf)
count2, secondHalf = mergeSortInversionCount(secondHalf)
firstN = len(firstHalf)
secondN = len(secondHalf)
secondHalfEnd = secondN
count3 = count1 + count2
# Count the inversions in the merge
# Uses a countdown through each sublist
for i in xrange(firstN-1, -1, -1):
x = firstHalf[i]
inversionFound = False
for j in xrange(secondHalfEnd-1,-1,-1):
if x > secondHalf[j]:
inversionFound = True
break
if inversionFound:
secondHalfEnd = j+1
count3 += j+1
mergeList = firstHalf + secondHalf
mergeList.sort()
return count3, mergeList
This just divides the list in half and counts the inversions, sorting the list as it goes. Merge sort is pretty efficient, algorithmically speaking (NlogN, though practically-speaking you could calculate it more quickly with some numpy matrices or by developing a minor adaptation to the C code for the underlying Python sorting algorithm. Technically, given that this approach transforms any type of variables into numbers, it's basically reduced to just a list-sorting approach, so you can use other element-wise list sorts to do the same thing, so long as you track the count.
With any of these methods (inversion counting, Levenstein, etc.), you can log the moves, clearly. Inversion counts log the swaps, logc noted a reasonable approach for logging some more general moves for Levenstein. Personally, I tend to use inversion counts for this because they're fairly simple. But it depends very much on what you want. If you need more operations than two-element neighbor swaps, Levenstein is a clear choice.
Perform a Cycle Sort and count the number of moves. That's guaranteed to be the minimum number.

Create multiple arrays based on frequency of coordinates in an array

Using JavaScript, I'd like to split one big array of coordinates into smaller arrays based on coinciding points. I am not 100% sure how to write the following in code but it describes what I'm attempting to achieve:
Iterate through the array
var A = [(1,2)(1,3)(2,3)(9,10)(9,11)(10,11)];
Combine the pairs that contain any matching/identical coordinate points:
var B = (1,2)(1,3)(2,3)
var C = (9,10)(9,11)(10,11)
Combine the matching/identical points and create new, smaller arrays from the combinations in point #2
var D = [1,2,3]
var E = [9,10,11]
Can I get help please?
Working answer: http://jsfiddle.net/y3h9L/
OK, so if I understand the requirement A is a one-dimensional array that is assumed to have an even number of elements in x,y pairs.
A = [1,2, 1,3, 2,3, 9,10, 9,11, 10,11]
// output should be
[ [1,2,3], [9,10,11] ]
// but if you add an extra pair that links the two halves, say add 2,11
A2 = [1,2, 1,3, 2,3, 9,10, 9,11, 10,11, 2,11]
// then all are related so output should be
[ [1,2,3,9,10,11] ]
I've made no effort to pretty-up or optimise the following code, but it works:
// single dimensional array of x,y pairs
var A = [1,2, 1,3, 2,3, 9,10, 9,11, 10,11];
// create a working copy of A so that we can remove elements
// and still keep the original A intact.
var workingCopy = A.slice(0, A.length),
matchedPairs = [],
currentMatches,
finalCombinations = [],
x, y, i, j,
tempArray;
while (workingCopy.length > 0) {
currentMatches = [];
currentMatches.push([workingCopy.shift(),workingCopy.shift()]);
workingCopyLoop:
for (x=0,y=1; x < workingCopy.length;) {
for (i=0; i < currentMatches.length; i++){
if (workingCopy[x] === currentMatches[i][0]
|| workingCopy[y] === currentMatches[i][1]) {
currentMatches.push([workingCopy.shift(),workingCopy.shift()]);
// go back to the beginning of workingCopyLoop
x=0;
y=1;
continue workingCopyLoop;
}
}
x += 2;
y += 2;
}
matchedPairs.push(currentMatches);
}
for (i=0; i<matchedPairs.length; i++){
tempArray = [];
for (j=0; j<matchedPairs[i].length; j++) {
// I assume you have a new enough version of JS that you have Array.indexOf()
if (-1 === tempArray.indexOf(matchedPairs[i][j][0]))
tempArray.push(matchedPairs[i][j][0]);
if (-1 === tempArray.indexOf(matchedPairs[i][j][1]))
tempArray.push(matchedPairs[i][j][1]);
}
finalCombinations.push(tempArray);
}
for (i=0; i<finalCombinations.length; i++)
console.log(finalCombinations[i]);
// console.log shows that finalCombinations = [ [1,2,3], [9,10,11] ]
If it's not obvious how this works, follow it through with a debugger and/or pencil and paper.
I must say your question is rather unclear, but i think i got it.
In other words what you're saying is:
I have an array containing a bunch of numbers, logically they represent coordinates, it's not that the coordinates are subarrays inside the master array, is just looking them 2 by 2, but it's a linear array.
What you want is something that detects coordinates that are adjacent and generate a new array containing them.
After that you want to go thru the new arrays and generate new arrays containing unique-elements.
Well that's the question, now the answer. First, the second point depends on how far you want to go, i'm thinking it's anormal grid of x,y coordinates, but how adjacent you want to go? The following just applies to the inmediate adjacent, up to 8 points can be adjacent to a single point.
[1,1][2,1][3,1]
[1,2][2,2][3,2]
[1,3][2,3][3,3]
May that be a representation of the grid, if your master array has the [2,2] coordinate, you want to build an array that begins with that one and all adjacents you find, lets say like master array has [3,2], then you want to add it to the subarray of [2,2].
I'm really not writing the code i'm just gonna explain sorts of algorithm you could use.
To build the second point arrays, lets call them Adjacents Arrays (AA) you could:
First coordinate will always build the first AA
To find adjacents you will cycle thru the master array and perform an "Adjacency Check" to every coordinate which would be: second x == ( first x-1, x or x+1) AND second y == ( first y-1, y or y+1), if it passes then pop/push, if not... next.
In case you finish cycling thru the master array means that AA is complete, and you have to start a new AA with the next coordinate.
Repeat until master array is empty.
Then to create the unique-element-array is quite a simple cycle, i wrote a similar function that does something like that but it creates an array with the element and how many times it appears in the array (instances):
function uniqueCnt( ori) { // agroups and counts unique elements of an array, scrubs '' elements
var res = []; // resulting array, ori parameter stands for original array
for( let cntA = 0; cntA < ori.length; cntA++) {
for( cntB = 0; cntB < res.length; cntB += 2) if( ori[cntA] == res[cntB]) { res[cntB + 1]++; break; } // if it matches means it's another instance then increase that element count
if( cntB == res.length && ori[cntA] != '') res.push( ori[cntA], 1); // New element found then push it and start count
}
return res; // returns the agrouped array 0:element 1:instances...
}
If you don't want a count of instances, then you would need an even simpler function, you could try modify this one.

Categories

Resources