how to discriminate two numbers that are very near? - javascript

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))

Related

Why does my JavaScript solution to problem 2 (project euler) show infinity on the console?

let arr=[0,1];
let sum=0;
for(let i=2;i<4000000;i++) {
arr.push(arr[i-1]+arr[i-2]);
}
for (let i=0;i<arr.length;i++) {
if (arr[i]%2==0) {
sum+=arr[i];
}
}
console.log(sum);
By considering the terms in the Fibonacci sequence whose values do not
exceed four million, find the sum of the even-valued terms.
My solution to this question is wrong and I can't figure out why at all. I am not that experienced so please if anyone can explain in a simple way why my code is wrong. What can I do to fix it??
Note: I haven't hadn't included code in this answer because I figure the point of what you're doing is to learn to code these things. (Now you've gotten most of the way there, I did add a solution at the end.)
The problem is that your sums quickly go beyond the range of what JavaScript's number type can represent, reaching the point where they just are represented by Infinity. The number type only has 53 effective significant bits in which to hold numbers. You're exceeding that:
let seen4M = false;
let seenInfinity = false;
let arr=[0,1];
let sum=0;
for(let i=2;i<4000000;i++) {
const num = arr[i-1]+arr[i-2];
if (!seen4M && num > 4_000_000) {
console.log(`Too big: ${num}`);
seen4M = true;
} else if (!seenInfinity && !isFinite(num)) {
console.log(`Overflowed just after ${arr[i-1]}`);
seenInfinity = true;
}
arr.push(num);
}
for (let i=0;i<arr.length;i++) {
if (arr[i]%2==0) {
sum+=arr[i];
}
}
console.log(sum);
You're doing four million (minus two) loops, but the question asks you to consider the Fibonacci numbers whose values are less than or equal to four million (4M), which is a very different thing and is reached much more quickly. So instead of (nearly) 4M loops, stop when your code determines that the next number is > 4M.
Also note that there's no reason to use an array for this, and doing so will consume a lot of memory unnecessarily. Instead, just remember the penultimate and ultimate values, and shuffle them in the loop. Maintain sum in the first loop rather than using a second one.
In a comment you showed that you'd solved it using an array but couldn't see how to solve it without using an array. Here's how to do that (see comments):
// The penultimate (second-to-last) Fibonacci number we've done
let pen = 0;
// The ultimate (last) Fibonacci number we've done
let ult = 1;
// The sum so far
let sum = 0;
// A variable for each number as we go
let num;
// Create the next number and keep looping if it's less than or
// equal to four million
while ((num = pen + ult) <= 4_000_000) {
// We have a new number (`num`), count it if appropriate
if (num % 2 == 0) {
sum += num;
}
// Now that we have a new number, shuffle the last two:
// our ultimate number is our penultimate number, and
// our ultimate number is the new one
pen = ult;
ult = num;
}
console.log(sum);

Converting a larger byte array to a string

When N is set to 125K the following works
let N = 125000
let x = [...Array(N)].map(( xx,i) => i)
let y = String.fromCodePoint(...x)
console.log(y.length)
When N is set to 128K that same code breaks:
Uncaught RangeError: Maximum call stack size exceeded
This is a common operation: what is the optimal way to achieve the conversion?
Note that I did look at this related Q&A . https://stackoverflow.com/a/3195961/1056563 We should not depend on node.js and also the approaches with the fromCharCode.apply are failing. Finally that answer is nearly ten years old.
So what is an up to date performant way to handle this conversion?
The problem is caused because implementations have limits to the number of parameters accepted. This results in an exception being raised when too many parameters (over ~128k in this case) are supplied to the String.fromCodePoint functions via the spread operator.
One way to solve this problem relatively efficiently, albeit with slightly more code, is to batch the operation across multiple calls. Here is my proposed implementation, which fixes what I perceive as issues relating to scaling performance and the handling of surrogate pairs (that's incorrect: fromCodePoint doesn't care about surrogates, making it preferable to fromCharCode in such cases).
let N = 500 * 1000;
let A = [...Array(N)].map((x,i) => i); // start with "an array".
function codePointsToString(cps) {
let rs = [];
let batch = 32767; // Supported 'all' browsers
for (let i = 0; i < cps.length; ){
let e = i + batch;
// Build batch section, defer to Array.join.
rs.push(String.fromCodePoint.apply(null, cps.slice(i, e)));
i = e;
}
return rs.join('');
}
var result = codePointsToString(A);
console.log(result.length);
Also, I wanted a trophy. The code above should run in O(n) time and minimize the amount of objects allocated. No guarantees on this being the 'best' approach. A benefit of the batching approach, and why the cost of apply (or spread invocation) is subsumed, is that there are significantly less calls to String.fromCodePoint and intermediate strings. YMMV - especially across environments.
Here is an online benchmark. All tests have access to, and use, the same generated "A" array of 500k elements.
The given answers are of poor performance: i measured 19 seconds on one of them and the others are similar (*). It is necessary to preallocate the output array. The following is 20 to 40 milli seconds. Three orders of magnitude faster.
function wordArrayToByteArray(hash) {
var result = [...Array(hash.sigBytes)].map(x => -1)
let words = hash.words
//map each word to an array of bytes
.map(function (v) {
// create an array of 4 bytes (less if sigBytes says we have run out)
var bytes = [0, 0, 0, 0].slice(0, Math.min(4, hash.sigBytes))
// grab that section of the 4 byte word
.map(function (d, i) {
return (v >>> (8 * i)) % 256;
})
// flip that
.reverse()
;
// remove the bytes we've processed
// from the bytes we need to process
hash.sigBytes -= bytes.length;
return bytes;
})
words.forEach((w,i) => {
result.splice(i * 4, 4, ...w)
})
result = result.map(function (d) {
return String.fromCharCode(d);
}).join('')
return result
}
(*) With the possible exception of #User2864740 - we are awaiting his numbers. But his solution also uses apply() inside the loop which leads to believe it will also be slow.
"Old fashion" JavaScript:
var N=125000;
var y="";
for(var i=0; i<N; i++)
y+=String.fromCharCode(i);
console.log(y.length);
Worked with N=1000000

Compute every combination of 6 numbers

I'm more of a media developer and not the best coder, but I find myself needing to learn javascript better. I'm creating a math card game where the human player and the automated player are each dealt 6 cards. Each player must combine (concatenate) three of the cards to make a top number and the other three for the bottom number. Those two numbers are then subtracted. For the automated player, I have to go through ever possible combination of the six cards, so when the two numbers are subtracted, it gets as close as possible to a target number. I'm not very good with arrays, so I started testing every possible combination and then comparing which one was closer (See example below). This is a very inefficient way of coding this, but I'm just not sure how to do it otherwise. Any help would be greatly appreciated.
The variables have already been declared.
alienTopNum = "" + alienNum1 + alienNum2 + alienNum3;
alienBottomNum = "" + alienNum4 + alienNum5 + alienNum6;
oldDiff = targetNum - (alienTopNum - alienBottomNum);
player.SetVar("AC1R1", alienNum1);
player.SetVar("AC2R1", alienNum2);
player.SetVar("AC3R1", alienNum3);
player.SetVar("AC4R1", alienNum4);
player.SetVar("AC4R1", alienNum5);
player.SetVar("AC4R1", alienNum6);
player.SetVar("ATR1", alienTopNum - alienBottomNum);
alienTopNum = "" + alienNum1 + alienNum2 + alienNum3;
alienBottomNum = "" + alienNum4 + alienNum6 + alienNum5;
newDiff = targetNum - (alienTopNum - alienBottomNum);
if (Math.abs(newDiff) < Math.abs(oldDiff)) {
oldDiff = newDiff;
player.SetVar("AC1R1", alienNum1);
player.SetVar("AC2R1", alienNum2);
player.SetVar("AC3R1", alienNum3);
player.SetVar("AC4R1", alienNum4);
player.SetVar("AC4R1", alienNum6);
player.SetVar("AC4R1", alienNum5);
player.SetVar("ATR1", alienTopNum - alienBottomNum);
}
etc....
Store the dealt cards in an array rather than in individual variables, because that makes them a lot easier to handle when generating permutations. You don't say what values the cards can have, but as an example, given a "hand" of [1,2,3,4,5,6] if you get the permutations as an array of arrays:
[ [1,2,3,4,5,6], [1,2,3,4,6,5], [1,2,3,5,4,6], ...etc. ]
Then you can loop through that to process each permutation to take the first three "cards" and last three to get the current iteration's two numbers, subtract them, and see if the result is closer to the target than previous iterations' results.
The following does that, making use of the array permutation function that I found in this answer to another question. I'm not going to explain that algorithm because you can easily google up various permutation algorithms for yourself, but I have put comments in my bestPlay() function to explain how I process the permutations to figure out which is the best score for a hand.
I haven't tried to use your player or player.SetVar() method, but hopefully if you study this you can adapt it to use with your objects.
You didn't say what values the cards could have, so I've assumed a deck of twenty cards that repeats the numbers 0-9 twice.
function bestPlay(hand, target) {
var perms = permutator(hand); // Get all permutations for hand
var best = perms[0]; // Use the first as initial best
var bestDiff = difference(best);
for (var i = 1; i < perms.length; i++) { // Loop over the rest of the permutations
var diff = difference(perms[i]); // Get diff for current permutation
if (Math.abs(target - diff) < Math.abs(target - bestDiff)) { // Check if
best = perms[i]; // current beats previous best
bestDiff = diff; // and if so make it new best
}
}
// Output the results for this hand:
console.log(`Hand: ${hand.join(" ")}`);
console.log(`Best Numbers: ${best.slice(0,3).join("")} ${best.slice(3).join("")}`);
console.log(`Difference: ${bestDiff}`);
}
var hands = deal();
var target = 112;
console.log(`Target: ${target}`);
bestPlay(hands[1], target);
bestPlay(hands[2], target);
function difference(cards) {
return Math.abs(cards.slice(0,3).join("") - cards.slice(3).join(""));
}
function deal() {
var cards = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0];
// shuffle
cards.sort(function() { return Math.random() - 0.5; });
// first hand is first six cards, second hand is next six
return {
1: cards.slice(0,6),
2: cards.slice(6, 12)
};
}
function permutator(inputArr) {
var results = [];
function permute(arr, memo) {
var cur, memo = memo || [];
for (var i = 0; i < arr.length; i++) {
cur = arr.splice(i, 1);
if (arr.length === 0) {
results.push(memo.concat(cur));
}
permute(arr.slice(), memo.concat(cur));
arr.splice(i, 0, cur[0]);
}
return results;
}
return permute(inputArr);
}
If you click the "Run Code Snippet" button several times you'll see that sometimes a given hand has a combination of numbers that exactly matches the target, sometimes it doesn't.

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.

Getting the lengthiest path in an array, functional style

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).

Categories

Resources