How to override JavaScript array sort method? - javascript

THIS QUESTION STILL HAS NOT BEEN CORRECTED ANSWERED AS OF Monday Oct 31 (People are wrongly answer it as if I'm asking for array.sort to be modified but I'm not asking that)
How do I override the built in JavaScript sort method for a single array (not Array.sort) with the radix-msd algorthim?
I have the algorithm for the radix msd sort, it's
// radix most-significant-bit sort for integers
//arr: array to be sorted
//begin: 0
//end: length of array
//bit: maximum number of bits required to represent numbers in arr
function radixsort (arr, begin, end, bit) {
var i, j, mask;
i = begin;
j = end;
mask = 1 << bit;
while(i < j) {
while(i < j && !(arr[i] & mask)) {
++i;
}
while(i < j && (arr[j - 1] & mask)) {
--j;
}
if(i < j) {
j--;
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
}
}
if(bit && i > begin) {
radixsort(arr, begin, i, bit - 1); // <=== RECURSIVE FUNCTION
}
if(bit && i < end) {
radixsort(arr, i, end, bit - 1); // <=== RECURSIVE FUNCTION
}
}
And my JavaScript object array is:
homes[0].price;
homes[0].address;
homes[0].city;
homes[0].state;
homes[0].zip;
So that, when I call "homes.sort()" - I want it to sort the entire homes[x] array based on the price using my radix sort array from above. How do I do that?

You don't need to override the sort function, you simply need to pass your comparer function to the sort method as a parameter.
The function signature for the parameter is function (a, b) where a is the item being compared to b.
If you need a different implementation of sort, set it as a different function rather than overriding the default behavior. You can do this for all arrays using:
Array.prototype.radixsort = function ( ...params... )
Which will allow you to call
[1,2,3].radixsort(...params...);
Alternatively, you can add a utility function to Array:
Array.radixsort = function ( ...params... )
Which will be called as:
Array.radixsort([1,2,3], ...params...);

I think modifying Array.prototype.sort is very dangerous (because all other codes probably using sort() will be affected). Here's the code though:
//Just use this function like radixsort(homes,0,homes.length,32)
function radixsort (arr, begin, end, bit) {
var i, j, mask;
i = begin;
j = end;
mask = 1 << bit;
while(i < j) {
while(i < j && !(arr[i].price & mask)) {
++i;
}
while(i < j && (arr[j - 1].price & mask)) {
--j;
}
if(i < j) {
j--;
var tmp = arr[i].price;
arr[i].price = arr[j].price;
arr[j].price = tmp;
i++;
}
}
if(bit && i > begin) {
radixsort(arr, begin, i, bit - 1);
}
if(bit && i < end) {
radixsort(arr, i, end, bit - 1);
}
}
//If you really want to modify default sort function:
Array.prototype.sort = function(){
radixsort(this,0,this.length,32); //Use 'this' to access (get reference) to the array.
}

Expanding on Ray Toal's and zzzzBov's discussion:
function defaultCompare(a, b) {
var a_str = str(a);
var b_str = str(b);
if (a_str < b_str) {
return -1;
} else if (a_str > b_str) {
return 1;
} else {
return 0;
}
}
homes.sort = function (compare_func) {
compare_func = compare_func || defaultCompare;
RadixSort(this, 0, this.length, 64);
}
There are probably typos in the above, but it should be a step toward a more complete implementation.

Your question is asking two things:
How does one call sort on an array but call a function other than Array.sort?
How do you make the sort algorithm use a particular field without hardcoding it?
The answer to the first question is to attach a sort method on the homes object itself:
homes.sort = function () {radixSort(homes, 0, homes.length, bit);}
As one of the commenters, and other answerers have pointed out, doing this can be very confusing. For one thing, Arrays.sort takes a second parameter which is a comparison function. Radix sort is a distribution-based sort, not a comparison-based sort, so "overriding" sort in this way doesn't make much sense. You would be ignoring a comparison function were someone to pass it in.
But there's another problem. Your radixSort as written does not work because it does not compare prices. One of the answers hardcodes the price, but you said you did not like this situation. You can fix this as follows: add a fifth parameter which is a field name. If undefined, use the array element itself, otherwise select the field. Something like this (not tested):
function radixsort (arr, begin, end, bit, field) {
var i = begin, j = end , mask = 1 << bit;
// Use the value of the field at i if present, otherwise the whole element
var at = function (i) {return field in arr ? arr[i][field] : arr[i]};
while (i < j) {
while (i < j && !(arr.at(i) & mask)) {
++i;
}
while (i < j && (arr.at(j-1) & mask)) {
--j;
}
if (i < j) {
j--;
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
}
}
if (bit && i > begin) {
radixsort(arr, begin, i, bit - 1);
}
if (bit && i < end) {
radixsort(arr, i, end, bit - 1);
}
}
Now you can say:
homes.sort = function () {radixSort(homes, 0, homes.length, 64, 'price');}
However, keep in mind the following caveat:
CAVEAT: If price is a floating-point value, a radix sort probably won't work. Your best bet is to just use Array.prototype.sort and pass in a comparator to sort on different fields.

Related

Implementing pseudocode in JavaScript

I'm quite new to JavaScript and I'm trying to implement my code in pseudocode in JavaScript, however I'm not getting the result that I'm supposed to. I want the function to permute the elements of the array p places to the left. In pseudocode I'm using a queue data structure, but I thought I can as well us an array. As the result of my function, I get an array with [2, 2, 2, 2]. Can you please help me out?
My code in pseudocode:
Function PERMUTEVECTOR(row, p)
If p=0 then
Return row
End if
New Queue q
For 0<= i <4 do
ENQUEUE[row[i], q]
End for
For 1<= i <= p do
ENQUEUE[HEAD[q],q]
DEQUEUE[q]
End for
For 0<=i<4 do
Row[i] <- HEAD[q]
DEQUEUE[q]
End for
Return row
End function
My code in JavaScript:
function permute_vector(row, p)
{
if (p=0)
{return row}
let q = new Array()
for (i=0; i<4; i++)
{
q.push(row[i])
}
for (i=0; i<p; i++)
{
q.push(q[0])
q.pop()
}
for (i=0; i<4; i++)
{
row[i] = q[0]
q.pop()
}
return row
}
px = permute_vector([2,4,1,3], 1)
console.log("px is:", px)
}
I did the same in Python and it works fine:
def permute_vector(row, p):
if p==0:
return row
q = []
for i in range(4):
q.append(row[i])
for i in range(p):
q.append(q[0])
q.pop(0)
for i in range(4):
row[i] = q[0]
q.pop(0)
return row
What am I doing wrong with my JavaScript code?
Many thanks!
In javascript, Array.pop() removes the last element. You need Array.shift() for removing the first one.
function permute_vector(row, p)
{
if (p===0) // in js, checks are with == (loose) or === (strict).
// = is for assignment and you were assigning p to 0 here.
{return row}
let q = new Array()
for (i=0; i<4; i++)
{
q.push(row[i])
}
for (i=0; i<p; i++)
{
q.push(q[0])
q.shift() // shift instead of pop
}
for (i=0; i<4; i++)
{
row[i] = q[0]
q.shift() // shift instead of pop
}
return row
}
px = permute_vector([2,4,1,3], 1)
console.log("px is:", px)
}
Two mistakes:
Comparisons need double or triple equal signs. In fact, you should prefer triple equal signs as you can read in this question/answer.
In python pop() accepts an index to remove a specific item. You're making use of that to remove the first item. In JavaScript Array.pop() merely is capable of removing the last item. Use Array.shift() to remove the first item.
Working code:
function permute_vector(row, p) {
if (p === 0) {
return row;
}
let q = new Array();
for (i = 0; i < 4; i++) {
q.push(row[i]);
}
for (i = 0; i < p; i++) {
q.push(q[0]);
q.shift();
}
for (i = 0; i < 4; i++) {
row[i] = q[0];
q.shift();
}
return row;
}
px = permute_vector([2, 4, 1, 3], 1);
console.log("px is:", px);
Now when you've got it, you can just ditch the whole thing and replace it with
vec[n:] + vec[:n] (Python)
[...vec.slice(n), ...vec.slice(0, n)] (JS)
Basic textbook algorithms are rarely useful in scripting languages, because they implement stuff like this out of the box.

Optimizing node.js solution for HackerRank QHEAP1

Hi I'm trying to familiarize myself a bit better with Heaps so wanted to try and implement a solution to HackerRanks>Practice>Data Structures>Heaps>QHEAP1 using primitives, however I'm getting a timeout error for two of the tests.
A quick summary: I need to be able to parse a standardized input and handle the following 3 types of queries:
Add an element to the heap.
Delete a specific element from the heap.
Print the minimum of all the elements in the heap.
I'm wondering where this could be optimized? From what I can tell my del() will be performed in O(n) since I need to search for the element provided.
// search for and delete specific element {x} from heap
function del(arr, x){
let i = 0;
let found = false;
let n = arr.length;
while(!found && i < n){
if(arr[i] == x) found = true;
i++;
}
if(found){
arr[i-1] = arr[n-1]; // take the last element and overwrite to delete
arr.length = n - 1; // shorten array
downHeap(arr, i); // perform downHeap opertaion from index deleted
}
}
// NOTE: customized for minHeap due to requirement to print minimum value
function downHeap(arr, t){
// use array as binary tree - next index looking down is double current index
// NOTE: i and t are 1 indexed for heap lookahead
let i = 2 * t;
if(i >= arr.length) return; // no more room
// checkes if right child is smallest - if so updates index to right child
if(i < arr.length - 1 && arr[i - 1] > arr[i]) i = i + 1;
// if lower element is smaller than current element, swap em
if(arr[i-1] < arr[t-1]){
swap(arr, i-1, t-1);
downHeap(arr,i); // downHeap again at the next level
}
}
// insert x into heap
function insert(arr, x){
const n = arr.length;
arr.length = n + 1; // increasing array size
arr[n] = x; // adding el to end of array
upHeap(arr, arr.length)
}
//NOTE: customized as minHeap due to requirement to print minimum value.
function upHeap(arr, t){
// using array as binary tree - looking up - parant is half of current index
const i = Math.floor(t/2);
// if we've hit zero gone too far - NOTE: i, and t are 1 indexed for heap reference
// also nothing to do if parent is smaller than current index
if(i == 0 || arr[i-1] <= arr[t-1]) return;
// child is smaller than parent swap and upHeap from parent
swap(arr, t-1, i-1)
upHeap(arr, i)
}
// swahp
function swap(arr, l, r){
const t = arr[l];
arr[l] = arr[r];
arr[r] = t;
}
PS. as a side question, I'm kind of switching between a 1 indexed for heap operations, and a 0 index for array operations (e.g. you'll notices a lot of i-1 statements inside the up and downHeap methods) - wondering if there's a smarter way of having done that?
Support Code:
function processData(input) {
//Enter your code here
const inputs = input.split('\n');
const n = inputs[0];
let arr = [];
for(let i = 1; i <= n; i++){
const query = inputs[i].split(' ');
const op = query[0];
if(op == "1"){
insert(arr, parseInt(query[1]))
} else if(op == "2"){
del(arr, parseInt(query[1]))
} else if(op == "3"){
console.log(arr[0])
} else {
console.log("Error reading op");
}
}
}
process.stdin.resume();
process.stdin.setEncoding("ascii");
_input = "";
process.stdin.on("data", function (input) {
_input += input;
});
process.stdin.on("end", function () {
processData(_input);
});
Example Input
22
1 286789035
1 255653921
1 274310529
1 494521015
3
2 255653921
2 286789035
3
1 236295092
1 254828111
2 254828111
1 465995753
1 85886315
1 7959587
1 20842598
2 7959587
3
1 -51159108
3
2 -51159108
3
1 789534713
The code is indeed confusing because (as you write) it sometimes uses 1-based indexes, while other times it uses them as 0-based.
For instance, in insert, the following line shows that you intend t and i to be a 1-based index, since you convert them on-the-fly to a 0-based index:
if(arr[i-1] < arr[t-1])
...but then in this line, you treat i as a 0-based index (arr.length would be an admissible value of i if it is 1-based):
if(i >= arr.length) return; // no more room
And the same mix-up happens here:
if(i < arr.length - 1 && arr[i - 1] > arr[i]) i = i + 1;
By consequence you will get wrong results.
It is confusing to work with 1-based indexes when JavaScript is expecting 0-based indexes everywhere indexes are used. I didn't feel the courage to further debug your code in that state. I would suggest to use 0-based indexes throughout your code, which means that the left child of a value at index t is at index t*2+1.
Some other remarks:
To find the index where a value occurs in the heap, you don't have to write an explicit loop. Just use the built-in indexOf method.
Recursion is nice, but the downHeap and upHeap functions will work more efficiently with an iterative method, because then -- instead of swapping values -- you can take a copy of the value to bubble up or down, and then only move (not swap) the conflicting values to finally insert the copied value in its right place. This will perform fewer assignments than swapping repeatedly.
To insert a value you can just use the push method instead of updating the length "manually".
Instead of Math.floor for the integer division by 2, you can use a shift operator.
So here is a correction of your code:
function del(arr, x) {
const i = arr.indexOf(x); // This will be faster
if (i >= 0) {
const value = arr.pop();
if (i < arr.length) { // Only assign back when it was not last
arr[i] = value;
downHeap(arr, i);
}
}
}
function downHeap(arr, t) {
const val = arr[t];
while (true) {
let i = t * 2 + 1;
if (i < arr.length - 1 && arr[i] > arr[i + 1]) i = i + 1;
if (i >= arr.length || arr[i] >= val) break;
arr[t] = arr[i]; // Don't swap to gain time
// No recursion to save stack space
t = i;
}
arr[t] = val;
}
function insert(arr, x) {
arr.push(x); // adding element to end of array
upHeap(arr, arr.length - 1);
}
function upHeap(arr, t) {
const val = arr[t];
while (true) {
let i = (t - 1) >> 1; // Shift operator may give some speed increase
if (i < 0 || arr[i] <= val) break;
arr[t] = arr[i]; // Don't swap to gain time
// No recursion to save stack space
t = i;
}
arr[t] = val;
}

How to use dynamic programming through Levenshtein algorithm (in Javascript)

I'm trying to understand dynamic programming through Levenshtein algorithm, but I have been stuck on this for a few hours now. I know my attempt at the following problem is the 'brute force' one. How would I use "dynamic programming" to change my approach? I'm pretty lost....
Problem: Given two strings, s and t, with lengths of n and m, create a
function that returns one of the following strings: "insert C" if
string t can be obtained from s by inserting character C "delete C"
(same logic as above) "swap c d" if string t can be obtained from
string s by swapping two adjacent characters (c and d) which appear in
that order in the original string. "Nothing" if no operation is
needed "impossible" if none of the above works ie LevenShtein distance is greater than 1.
Here is my brute force attempt. the "tuple" variable is misnamed as I originally wanted to push the indices and values to the matrix but got stuck on that.
function levenshtein(str1, str2) {
var m = str1.length,
n = str2.length,
d = [],
i, j,
vals = [],
vals2 = [];
for (i = 0; i <= m ; i++) {
var tuple = [str1[i]];
//console.log(tuple);
// console.log(tuple);
d[i] = [i];
// console.log(str1[i]);
vals.push(tuple);
}
vals = [].concat.apply([], vals);
vals = vals.filter(function(n){ return n; });
console.log(vals);
for (j = 0; j <= n; j++) {
d[0][j] = j;
var tuple2 = [str2[j]];
// console.log(tuple2);
vals2.push(tuple2);
// console.log(vals2);
}
vals2 = [].concat.apply([], vals2);
vals2 = vals2.filter(function(n){ return n ;});
console.log(vals2);
for (j = 1; j <= n; j++) {
for (i = 1; i <= m; i++) {
if (str1[i - 1] == str2[j - 1]) d[i][j] = d[i - 1][j - 1];
else d[i][j] = Math.min(d[i - 1][j], d[i][j - 1], d[i - 1][j - 1]) + 1;
}
}
var val = d[m][n];
// console.log(d);
if(val > 1){
return "IMPOSSIBLE";
}
if(val === 0){
return "NOTHING";
}
//console.log(d);
if(val === 1){
//find the missing element between the vals
//return "INSERT " + missing element
//find the extra element
//return "DELETE + " extra element
//find the out of place element and swap with another
}
}
console.log(levenshtein("kitten", "mitten"));
// console.log(levenshtein("stop", "tops"));
// console.log(levenshtein("blahblah", "blahblah"));
The problem as described cannot be optimized using dynamic programming because it only involves a single decision, not a series of decisions.
Note that the problem specifically states that you should return "impossible" when the Levenshtein distance is greater than 1, i.e., the strings can't be made equal through a single operation. You need to be searching for a sequence of zero or more operations that cumulatively result in the optimal solution if you want to apply dynamic programming. (This is what the dynamic programming wikipedia article is talking about when it says you need "optimal substructure" and "overlapping subproblems" for dynamic programming to be applicable.)
If you change the problem to calculate the full edit distance between two strings, then you can optimize using dynamic programming because you can reuse the result of choosing to do certain operations at a particular location in the string in order to reduce the complexity of the search.
Your current solution looks a bit overly complex for the given problem. Below a simpler approach you can study. This solution takes advantage of the fact that you know you can only do at most one operation, and you can infer which operation to attempt based off the difference between the lengths of the two strings. We also know that it only makes sense to try the given operation at the point where the two strings differ, rather than at every position.
function lev(s, t) {
// Strings are equal
if (s == t) return "nothing"
// Find difference in string lengths
var delta = s.length - t.length
// Explode strings into arrays
var arrS = s.split("")
var arrT = t.split("")
// Try swapping
if (delta == 0) {
for (var i=0; i<s.length; i++) {
if (arrS[i] != arrT[i]) {
var tmp = arrS[i]
arrS[i] = arrS[i+1]
arrS[i+1] = tmp
if (arrS.join("") == t) {
return "swap " + arrS[i+1] + " " + arrS[i]
}
else break
}
}
}
// Try deleting
else if (delta == 1) {
for (var i=0; i<s.length; i++) {
if (arrS[i] != arrT[i]) {
var c = arrS.splice(i, 1)[0]
if (arrS.join("") == t) {
return "delete " + c
}
else break
}
}
}
// Try inserting
else if (delta == -1) {
for (var i=0; i<t.length; i++) {
if (arrS[i] != arrT[i]) {
arrS.splice(i, 0, arrT[i])
if (arrS.join("") == t) {
return "insert " + arrS[i]
}
else break
}
}
}
// Strings are too different
return "impossible"
}
// output helper
function out(msg) { $("body").append($("<div/>").text(msg)) }
// tests
out(lev("kitten", "mitten"))
out(lev("kitten", "kitten"))
out(lev("kitten", "kitetn"))
out(lev("kiten", "kitten"))
out(lev("kitten", "kittn"))
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Sorting strings from prompt is not working but it works when hard coded

My code is not working when I give the value via prompt but is working with hard coded input.
Could someone please help me understand why that is?
var str=prompt("Enter String :: ");
alert(selectionSort(str));
function selectionSort(items){
var len = items.length,
min;
for (i=0; i < len; i++){
min = i;
//check the rest of the array to see if anything is smaller
for (j=i+1; j < len; j++){
if (items[j] < items[min]){
min = j;
}
}
if (i != min){
swap(items, i, min);
}
}
return items;
}
This is my swapping function:
function swap(items, firstIndex, secondIndex){
var temp = items[firstIndex];
items[firstIndex] = items[secondIndex];
items[secondIndex] = temp;
}
If you just want to sort the characters you can use:
var str = "farhan";
var sorted = str.split("").sort().join("");
console.log(sorted); // "aafhnr"
.split("") turns the string into an array. .sort sorts the array (default is ascending order) and .join("") turns the array back into a string.
For educational purposes it might be useful to write your own sort routine, but beyond that, use the built in functions as much as you can.

Search closest next value in javascript array

I have a javascript array like var test = [2,5,8,12,56]; and now I want to search the closest next value of 9. So the output is 12 in this case (and not 8!).
Well here's a simple way to do it:
function getNextVal(arr, val) {
// omit the next line if the array is always sorted:
arr = arr.slice(0).sort(function(a,b){return a-b;});
for (var i=0; i < arr.length; i++)
if (arr[i] >= val)
return arr[i];
// return default value when val > all values in array
}
You don't say what to return if the search value is in the array, so I've assumed you want to return it. If by "closest next value" you meant that it should always return the next number higher than the search value change arr[i] >= val to use > instead of >=.
If you have a large array you probably want some kind of binary sort instead of just going through from the beginning.
Here is what you can try if the array is sorted, you need to tune for for boundry cases, this is just for idea of algorithm...
NUM is input
TEST is your array
INDEX is index variable
For INDEX from 0 .. TEST.SIZE -1
IF NUM > TEXT[INDEX]
RETURN TEXT[INDEX]
A very simple code is given below. Hope this will help you
var test = [2,5,8,12,56];
var key = 9;
var closestNext=1000;
for(var i=0;i<test.length;i++)
{
if(test[i] > key)
{
if(test[i]<closestNext)
{
closestNext = test[i];
}
}
}
alert(closestNext);
​
see the working one here
1 Start by sorting the array, using arr.sort();, just sorts the values in the ascending order (3,6,4,7,1 --> 1,3,4,6,7), then just iterate:
function getNext(inputVal,arr)
{
arr.sort();;
for (var i=0;i<arr.lenght;i++)
{
if (arr[i] >= inputVal)
{
return arr[i];
}
}
throw new Error('Out of range');
}
If you know the array is always going to be sorted or if it is reasonable to sort the array beforehand (e.g. when the array doesn't change very often but you need a lot of retrievals), you can use a binary search on the sorted array.
If the value is not found in the array, the upper bound is returned which indicates the smallest element greater than the given value. This gives O(log n) complexity on average whereas the naive approach (looping over the whole array) gives O(n) complexity on average.
// Binary search
// Adapted from http://jsfromhell.com/array/search
function binarySearch(arr, val, insert) {
var high = arr.length, low = -1, mid;
while (high - low > 1) {
mid = (high + low) >> 1;
if (arr[mid] < val) low = mid;
else high = mid;
}
if (arr[high] == val || insert) {
return high;
} else {
return -1;
}
}
function getClosestNext(arr, val) {
// Get index
var i = binarySearch(arr, val, true);
// Check boundaries
return (i >= 0 && i < arr.length) ? arr[i] : null;
}

Categories

Resources