What is the default sort for 2D arrays? - javascript

when using Array.sort()
I would assume it takes the first index but I wanted to verify.
MDN reference did not say anything:
This SO Post is not relevant.
For this method: ( sorting off the first index will work fine ).
$P.aZindex = function () {
var arr_2d = {},
elements = document.body.getElementsByTagName("*"),
element,
length,
z_index;
// loop through elements and pull information from them
$A.eachIndex(elements, function(val, index){
z_index = win.getComputedStyle(val).getPropertyValue("z-index");
// ignore elements with the auto value
if (z_index !== "auto") {
arr_2d[i] = [val.id, val.tagName, val.className, z_index];
}
});
// sort the array
arr_2d.sort();
return arr_2d;
};

Let's examine the EMCAScript specification for the array sort method. The sort algorithm iteratively compares pairs of elements from the array; those comparisons yield either -1, 1, or 0 (for less than, greater than, or equal to, respectively), and the result of each comparison is used to build a sorted array.
In particular, we are concerned with the "default" comparison case of sort, in which no comparison function is specified. When comparing some pair of x and y:
Let xString be ToString(x).
Let yString be ToString(y).
If xString < yString, return −1.
If xString > yString, return 1.
Return +0.
ECMAScript's ToString, when applied to objects, calls the object's toString method.
To clarify what is meant by x > y and x < y, we can examine ECMAScript's Abstract Relational Comparison Algorithm, which specifies the behavior of the > and < operators. In the event that the operands px and py are both strings:
Let k be the smallest nonnegative integer such that the character at position k within px is different from the character at position k within py...
Let m be the integer that is the code unit value for the character at position k within px.
Let n be the integer that is the code unit value for the character at position k within py.
If m < n, return true. Otherwise, return false.
This is a simple string comparison, based on a comparison of Unicode code unit values of the character at the first differing position within the strings.
As you can see, the sort algorithm stringifies each object element (using the element's toString method) that it contains and then compares those strings to determine ordering. I understand that this seems strange to you: if you have nothing but array elements in your sorting array, why not use the elements of those subarrays to determine ordering? This is simply because the EMCAScript specification chose to keep default element comparison of a potentially heterogeneous array extremely general, since any type of element can be rendered as a string.
However, if array-descent behavior is what you want, it's possible to implement:
var compare_items = function(a,b) {
var result;
if(a instanceof Array && b instanceof Array) {
// iteratively compare items from each array
for(var i=0; i<Math.min(a.length,b.length); ++i) {
result = compare_items(a[i], b[i]);
if(result != 0) { return result; }
}
// if both arrays are equal so far, length is the determining factor
return a.length - b.length;
}
// if the items are both numbers, report their numeric relation
if(typeof a == "number" && typeof b == "number") {
return a - b;
}
// otherwise, fall back to strings
if(a.toString() == b.toString()) { return 0; }
return a.toString() > b.toString() ? 1 : -1;
}
Then, use this comparator function like arr_2d.sort(compare_items);.
This allows you to sort arbitrarily deep N-dimensional arrays. First we compare a[0]...[0][0] against b[0]...[0][0] then a[0]...[0][1] to b[0]...[0][1]; then, if the [0]...[0][*] subarray proves equal, we move up to a[0]...[1][0], etc. Comparing arrays of differing dimension may produce unusual results, because a non-array may be compared to an array, which compares the stringified forms of each operand.
Note that this function has strange results if you have a heterogeneous array: [1, 2, 3, [1,2], [2,3]] sorts to [1, [1,2], 2, [2,3], 3]. The arrays and non-array are relatively sorted correctly, but the arrays are scattered in with the non-arrays in a non-intuitive way.

From the documentation you link to:
the array is sorted lexicographically (in dictionary order) according to the string conversion of each element
This doesn't change just because those elements are also arrays.

Related

How to get sums of subarrays

While solving online code exercises, I came across this one:
Given a 1-dimensional array of numbers and the number of queries, where each query has start index a, end index b and a number c, find the sum of numbers between indexes a and b (inclusive). For each occurrence of zero within the range [a,b], add the value of c to the sum. For example, numbers = [4,6,0,10], queries = [1,3,20] => for this example we need to get the sum of [4,6,0] (indexes 1-3), and because [4,6,0] has 0, we also need to add 20.
This is my code so far:
function findSum(numbers, queries) {
//declare empty array that will store the numbers
let arr = []
// declare initial sum
let sum = 0;
// get the last element of queries (c)
let lastElement = queries[0].pop()
// loop through queries and push numbers to arr, to sum them in the end
queries[0].slice(0, 2).forEach(x => {
arr.push(numbers[x - 1])
})
// check if arr has 0
let zero = arr.filter(el => el === 0)
// if arr has 0, according to the instructions we need to add the c of the q
if (zero.length != 0) {
sum = arr.reduce((a, b) => a + b, 0) + lastElement
}
else {
sum = arr.reduce((a, b) => a + b, 0)
}
return sum
}
My code works if queries is an array, but in some test cases queries may be array of arrays like [ [ 2, 2, 20 ], [ 1, 2, 10 ] ]. I don't know know how to check the numbers in case if queries is array of arrays. Any suggestions are greatly appreciated.
in some test cases queries may be array of arrays
I would expect that this would always be the case, not just in some cases. This is also clear from your code:
queries[0].pop()
This assumes a 2-dimensional array! The problem is not that you sometimes get a 1-dimensional array and other times a 2-dimensional array. The problem is that although you always get a 2-dimensional array, your code is only looking at the first query -- the one that sits at queries[0].
Instead, you should loop over all queries.
I also assume that the return value of your function must be an array, having an answer for each of the queries. This means that you probably want to have code like this:
function findSum(numbers, queries) {
return queries.map(query => {
// solve the single query
return sum;
});
}
Note that your code is not making the sum correctly, as your arr will have a length of 2 (arr.push(numbers[x - 1]) is executed exactly twice), yet the query could indicate a range with 100 values and you should derive the sum of those 100 values, not just of two.
But even if you fix all that, you'll end up with an inefficient solution that will have to iterate over many values in the input array multiple times. This needs a smarter approach.
Try to think of a way to analyse the input before processing any queries yet. Would there be something useful you could build that would help to quickly get a sum of a subarray without having to iterate that subsection again?
Here are some hints:
Hint #1
Use the following truth:
sum(numbers.slice(start, end)) == sum(numbers.slice(0, end)) - sum(numbers.slice(0, start - 1))
Hint #2
What if you would know the sum from the start of the array to any given index? Like a running sum... So for numbers=[4, 8, 0, 3] you would know [4, 12, 12, 15]. Would that help in calculating a sum for a certain range of [start, end]?
Hint #3
How could you apply the same principle for the special treatment of zeroes?

Sort sting with numbers javascript

Hi can someone help me sort string with numbers in java script.
I want to sort these options using jquery according to their distance (9 km).
<select >
<option >Point a (9 km)</option>
<option >Point b (10 km)</option>
<option >Point c (2 km)</option>
</select>
Basically I just want to sort string that has some numbers in them.Another example.
input:
var arr = ['A (9 km)','B (10 km)','C (2 km)']
output:
C (2 km)
A (9 km)
B (10 km)
You got the point.
Thanks in advance,
Is this what you're after ?
const distances = ['A (9 km)','B (10 km)','C (2 km)'];
const sorted = distances
.map((x,i)=>[parseInt(x.replace(/[^\d]+/g,''),10),i])
.sort((a,b)=>a[0]-b[0])
.map(x=>distances[x[1]]);
console.log(sorted);
First we need to assign references to our DOM nodes. We'll call the parent selectContainer and its list of children to selectChildren.
Next we need a Regular Expression pattern to extract the value of interest that we're using to apply the sorting logic to. In this case we're extracting the digit number in the parenthesized km.
Finally, we cast the children elements to an array so it is iterable, allowing us to use the sort method.
Inside our sort method we are using our Regular Expression pattern to extrapolate the number value we care about.
const selectContainer = document.querySelector('select');
const selectChildren = selectContainer.querySelectorAll('option');
const pattern = /.*\((\d+)\skm\).*/;
const sorted = [...selectChildren].sort((a, b) => {
const _a = parseInt(a.innerText.match(pattern)[1]);
const _b = parseInt(b.innerText.match(pattern)[1]);
return _a < _b ? -1 : 1;
});
sorted.forEach(child => selectContainer.append(child));
Since you mentioned, multiple use cases, let's talk about the sorting parts. Once you have a collection of the strings, and the numbers, perhaps something in the form tuple, like so:
var pairs = [
[9, 'A (9 km)'],
[5, 'B (5 km)'],
[5, 'C (5 km)']
];
You can tackle the problem in any number of ways, let's start with a few simple
built in array functions, such as sort and map.
Sort, is an array function which takes a "comparator" function, which you design, to sort an array.
Here is a simple example of the "comparator" function, assuming you have a collection of tuples, as I outlined above:
function compareDistanceTuples(a, b) {
// is A less than B?
if (a[0] < b[0]) {
return -1;
}
// is A grater than B?
if (a[0] > b[0]) {
return 1;
}
// A must be equal to B
return 0;
}
Now you can use sort and map, along with your new "comparator" to generate your
sorted list, like so:
var sorted = pairs.sort(compareDistanceTuples).map(function(tuple){
return tuple[1];
});
You cant expect to write a generic function that will know how to compare any string based on any numbers inside of it. Trying to sort any kind of string this way is that it is very specific to your use case. Here, we have to believe that the number we care about will be inside of parenthesis and followed by km.
Sorting Requires providing a comparison function to your array.sort(). Given this specific use case, I used a regex to pull out the number from your string and then compare numbers.
//input:
var arr = ['A (9 km)', 'B (10 km)', 'C (2 km)'];
arr.sort((a, b) => {
const regEx = /\((\d+)\s{1}km\)/;
const aNumMatch = a.match(regEx);
const aNum = aNumMatch[1]
const bNumMatch = b.match(regEx);
const bNum = bNumMatch[1];
return (aNum - bNum);
});
for(let index = 0; index < arr.length; index++){
console.log(arr[index]);
}
You can sort any array in-place using Array.prototype.sort.
The meat of the operation is extracting the number from the string, which I assume you can do already based on another comment. Let's assume your function that can do this pointToNumber(pointStr)
For anyone else coming to this question later, Number.parseInt(str.replace(/[^\d]/g, ''), 10) would probably accomplish it if you know that your string will only have a single number in it.
That said, here is how you can sort such an array:
const arr = ['A (9 km)','B (10 km)','C (2 km)']
arr
.map(point => [pointToNumber(point), point])
.sort(([a], [b]) => {
return a - b;
})
.map(([, point]) => point);
The real magic here is in a - b. This is because a sorting comparator function can return either 0, -1 (or any negative number), or 1 (or any positive number).
As mentioned in the linked msdn, returning a negative number causes a to be sorted into an index lower than b, and returning a positive one causes a to be sorted into an index higher than b.
a - b in a comparator is a shorthand way of writing out that we want to sort in ascending order, because when a > b it will return a positive number so that a moves up, when a < b it returns a negative one so a moves down, and when they're the same it returns zero.
(you could also use b - a if you want descending)

Explanation of .sort in JavaScript [duplicate]

How does the following code sort this array to be in numerical order?
var array=[25, 8, 7, 41]
array.sort(function(a,b){
return a - b
})
I know that if the result of the computation is...
Less than 0: "a" is sorted to be a lower index than "b".
Zero: "a" and "b" are considered equal, and no sorting is performed.
Greater than 0: "b" is sorted to be a lower index than "a".
Is the array sort callback function called many times during the course of the sort?
If so, I'd like to know which two numbers are passed into the function each time. I assumed it first took "25"(a) and "8"(b), followed by "7"(a) and "41"(b), so:
25(a) - 8(b) = 17 (greater than zero, so sort "b" to be a lower index than "a"): 8, 25
7(a) - 41(b) = -34 (less than zero, so sort "a" to be a lower index than "b": 7, 41
How are the two sets of numbers then sorted in relation to one another?
Please help a struggling newbie!
Is the array sort callback function called many times during the course of the sort?
Yes
If so, I'd like to know which two numbers are passed into the function each time
You could find out your self with:
array.sort((a,b) => {
console.log(`comparing ${a},${b}`);
return a > b ? 1
: a === b ? 0
: -1;
});
EDIT
This is the output I've got:
25,8
25,7
8,7
25,41
The JavaScript interpreter has some kind of sort algorithm implementation built into it. It calls the comparison function some number of times during the sorting operation. The number of times the comparison function gets called depends on the particular algorithm, the data to be sorted, and the order it is in prior to the sort.
Some sort algorithms perform poorly on already-sorted lists because it causes them to make far more comparisons than in the typical case. Others cope well with pre-sorted lists, but have other cases where they can be "tricked" into performing poorly.
There are many sorting algorithms in common use because no single algorithm is perfect for all purposes. The two most often used for generic sorting are Quicksort and merge sort. Quicksort is often the faster of the two, but merge sort has some nice properties that can make it a better overall choice. Merge sort is stable, while Quicksort is not. Both algorithms are parallelizable, but the way merge sort works makes a parallel implementation more efficient, all else being equal.
Your particular JavaScript interpreter may use one of those algorithms or something else entirely. The ECMAScript standard does not specify which algorithm a conforming implementation must use. It even explicitly disavows the need for stability.
Pairs of values are compared, one pair at a time. The pairs that are compared are an implementation detail--don't assume they will be the same on every browser. The callback can be anything (so you can sort strings or Roman numerals or anything else where you can come up with a function that returns 1,0,-1).
One thing to keep in mind with JavaScript's sort is that it is not guaranteed to be stable.
Deeply Knowledge
If the result is negative a is sorted before b.
If the result is positive b is sorted before a.
If the result is 0 no changes are done with the sort order of the two values.
NOTE:
This code is the view inside of the sort method step by step.
OUTPUT:
let arr = [90, 1, 20, 14, 3, 55];
var sortRes = [];
var copy = arr.slice(); //create duplicate array
var inc = 0; //inc meant increment
copy.sort((a, b) => {
sortRes[inc] = [ a, b, a-b ];
inc += 1;
return a - b;
});
var p = 0;
for (var i = 0; i < inc; i++) {
copy = arr.slice();
copy.sort((a, b) => {
p += 1;
if (p <= i ) {
return a - b;
}
else{
return false;
}
});
p = 0;
console.log(copy +' \t a: '+ sortRes[i][0] +' \tb: '+ sortRes[i][1] +'\tTotal: '+ sortRes[i][2]);
}
To help clarify the behavior of Array#sort and its comparator, consider this naive insertion sort taught in beginning programming courses:
const sort = arr => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && arr[j-1] > arr[j]; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array);
console.log("" + array);
Ignoring the choice of insertion sort as the algorithm, focus on the hardcoded comparator: arr[j-1] > arr[j]. This has two problems relevant to the discussion:
The > operator is invoked on pairs of array elements but many things you might want to sort such as objects don't respond to > in a reasonable way (the same would be true if we used -).
Even if you are working with numbers, oftentimes you want some other arrangement than the ascending sort that's been baked-in here.
We can fix these problems by adding a comparefn argument which you're familiar with:
const sort = (arr, comparefn) => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array, (a, b) => a - b);
console.log("" + array);
sort(array, (a, b) => b - a);
console.log("" + array);
const objArray = [{id: "c"}, {id: "a"}, {id: "d"}, {id: "b"}];
sort(objArray, (a, b) => a.id.localeCompare(b.id));
console.log(JSON.stringify(objArray, null, 2));
Now the naive sort routine is generalized. You can see exactly when this callback is invoked, answering your first set of concerns:
Is the array sort callback function called many times during the course of the sort? If so, I'd like to know which two numbers are passed into the function each time
Running the code below shows that, yes, the function is called many times and you can use console.log to see which numbers were passed in:
const sort = (arr, comparefn) => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
console.log("on our version:");
const array = [3, 0, 4, 5];
sort(array, (a, b) => console.log(a, b) || (a - b));
console.log("" + array);
console.log("on the builtin:");
console.log("" +
[3, 0, 4, 5].sort((a, b) => console.log(a, b) || (a - b))
);
You ask:
How are the two sets of numbers then sorted in relation to one another?
To be precise with terminology, a and b aren't sets of numbers--they're objects in the array (in your example, they're numbers).
The truth is, it doesn't matter how they're sorted because it's implementation-dependent. Had I used a different sort algorithm than insertion sort, the comparator would probably be invoked on different pairs of numbers, but at the end of the sort call, the invariant that matters to the JS programmer is that the result array is sorted according to the comparator, assuming the comparator returns values that adhere to the contract you stated (< 0 when a < b, 0 when a === b and > 0 when a > b).
In the same sense that I have the freedom to change my sort's implementation as long as I don't breach my specification, implementations of ECMAScript are free to choose the sort implementation within the confines of the language specification, so Array#sort will likely produce different comparator calls on different engines. One would not write code where the logic relies on some particular sequence of comparisons (nor should the comparator produce side effects in the first place).
For example, the V8 engine (at the time of writing) invokes Timsort when the array is larger than some precomputed number of elements and uses a binary insertion sort for small array chunks. However, it used to use quicksort which is unstable and would likely give a different sequence of arguments and calls to the comparator.
Since different sort implementations use the return value of the comparator function differently, this can lead to surprising behavior when the comparator doesn't adhere to the contract. See this thread for an example.
Is the array sort callback function called many times during the course of the sort?
Yes, that's exactly it. The callback is used to compare pairs of elements in the array as necessary to determine what order they should be in. That implementation of the comparison function is not atypical when dealing with a numeric sort. Details in the spec or on some other more readable sites.
Is the array sort callback function called many times during the course of the sort?
Since this is a comparison sort, given N items, the callback function should be invoked on average (N * Lg N) times for a fast sort like Quicksort. If the algorithm used is something like Bubble Sort, then the callback function will be invoked on average (N * N) times.
The minimum number of invocations for a comparison sort is (N-1) and that is only to detect an already sorted list (i.e. early out in Bubble Sort if no swaps occur).
Is the array sort callback function called many times during the course of the sort?
Yes
If so, I'd like to know which two numbers are passed into the function each time.
a: The first element for comparison.
b: The second element for comparison.
In the following example, a will be "2" and b will be "3" in the first iteration
How are the two sets of numbers then sorted in relation to one another?
Elements are sorted according to the return value of the compare function.
greater than 0: sort a after b
less than 0: sort a before b
equal to 0: keep original order of a and b
Here is an example
var arr = [3, 2, 1, 5, 4, 6, 7, 9, 8, 10];
console.log(arr.sort((a, b) => {
console.log(a - b, a, b);
//b-a if sorting in decending order
return a - b;
}));

Check equality between N > 2 arrays with maximum performance?

I'd like to check if n arrays all contain the same integers in JavaScript? What is the most efficient way?
if you have only numbers in the arrays - use some variation of the basic CRC algorithm - the complexity is O(n) per array so it would be the fastest possible https://en.wikipedia.org/wiki/Cyclic_redundancy_check
Similar idea, calculate sum(array) and product(array), you can calculate both values with O(n). For example:
1, 5, 6, 7 ,8 sum=27, prod=1680
7, 8, 1, 5, 6 sum=27, prod=1680
but
3, 8, 5, 5, 6 sum=27, prod=3600
NOTE special case is 0! Since that will nullify the product this all values should be used +1.
NOTE2
Keep in mind that the idea behind CRC algorithms is to use one byte or dword variable for the total and the variable will eventually overflow.
For example in the case of byte: 250 + 10 = 5, as the byte overflows at 255. However it is okay as both arrays would overflow and the chance for false report is very small. I believe that if we can try hard we can prove it mathematically that is okay.
However, If you lazy to do the math and absolute certainty is required you can use this method quick filtering of all negative candidates and then sort+compare only the positive candidates. Still will be way faster than using only sort+compare.
NOTE3:
Just realized you're using JS and JS is a bit messy with big numbers and doesn't really overflow with arithmetical operations.
However it does overflow with logical operators and the CRC algorithm does use xor so you are good. This is the CRC algo:
https://en.wikipedia.org/wiki/Cyclic_redundancy_check
And this is some open source implemention: https://github.com/emn178/js-crc/blob/master/src/crc.js
On prima vista seems to follow the algorithm, however I am not sure how quality it is, so do your due diligence!
This solution avoids using sort, making the algorithm O(n²), where n is the number of and lengths of the arrays. It has the added benefit of not mutating the arrays and also let's you pass arrays containing any types, not just numbers. It operates by computing a frequency bag for each array item, then assessing whether they all hold the same data. The toBag and bagsEqual functions are both O(n). This makes the main algorithm arraysSame O(n²). Using sort instead of frequency bags would make the solution O(n²log(n)), which isn't nearly as favorable.
function arraysSame(...arrays) {
if(arrays.length < 2) return true;
let bag1 = toBag(arrays[0]);
for(let i = 1; i < arrays.length; i++) {
const bag2 = toBag(arrays[i]);
if(!bagsEqual(bag1, bag2)) return false;
}
return true;
}
function bagsEqual(bag1, bag2) {
if(bag1.size != bag2.size) return false;
for(const [key, value] of bag1) {
if(!bag2.has(key)) return false;
if(value != bag2.get(key)) return false;
}
return true;
}
function toBag(array) {
const bag = new Map();
for(const val of array) {
const count = bag.get(val) || 0;
bag.set(val, count + 1);
}
return bag;
}

javascript: how to make function run faster

so i have to write a function which meets the following requirements:
Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
Example:
For sequence = [1, 3, 2, 1], the output should be
almostIncreasingSequence(sequence) = false;
There is no one element in this array that can be removed in order to get a strictly increasing sequence.
For sequence = [1, 3, 2], the output should be
almostIncreasingSequence(sequence) = true.
You can remove 3 from the array to get the strictly increasing sequence [1, 2]. Alternately, you can remove 2 to get the strictly increasing sequence [1, 3].
Input/Output
[time limit] 4000ms (js)
[input] array.integer sequence
Guaranteed constraints:
2 ≤ sequence.length ≤ 105,
-105 ≤ sequence[i] ≤ 105.
so my code works except for one problem--there are 30 tests it has to pass with the time constraint of 4000ms, but it always times out on the 30th test, every time. i have tried modifying it so that it runs faster, but each time i do so it no longer works correctly. although i technically only have to write one function, i broke it up into three separate functions. here's my code:
var greater = function(a, b) {
if (a < b) {
return true
} else {
return false
}
}
function greaterThan(arr) {
for (var i = 0; i < arr.length-1; i++) {
var curr = arr[i]
var next = arr[i + 1]
if (greater(curr, next) === false) {
return false
}
}
return true
}
function almostIncreasingSequence(sequence) {
for(var i = 0; i < sequence.length; i++) {
var newArr = sequence.slice()
newArr.splice(i, 1)
if (greaterThan(newArr) === true) {
return true
}
}
return false
}
so how can i make it run faster without using two for-loops/iterations to do this?
Improving the algorithm may bring better results than improving the code. Here's the problem:
If the sequence is not strictly increasing at index i, such that a[i]>=a[i+1] is true, either a[i] or a[i+1] must be removed to possibly make the array strictly increasing - they can't both be left in place.
If the input array is to be fixable by removing only one element, and it decreases after the ith element it must become strictly increasing by removing the element with subscript i or (i+1).
Compare the efficiency of checking the original array and at most two sub arrays before returning true or false, with checking the same number of arrays as the original array's length. I'll leave re-writing the code to you - it's not my homework :-)

Categories

Resources