This question already has answers here:
How to sort an array of integers correctly
(32 answers)
Closed 9 years ago.
Hello I have a textbox having values like
<input type="hidden" value="2,1,4,5,3,6,7,8,9,10,11,12" class="sortvalues" id="1_1_parent">
Now what I want to take the value of this textbox, want to split the values to array and then as last result I need a sorted array.
What I have done.
allsortedValues = $(".sortvalues").val();
allsortedValues = allsortedValues.split(",");
allsortedValues = allsortedValues.sort();
When I check the array
console.log(allsortedValues);
It shows
1,10,11,12,2,3,4,5,6,7,8,9
Sorting array as 1, 10, 11, 12, 2.....
I have even used
allsortedValues = allsortedValues.split(",").map(function(x){return parseInt(x)});
before applying sort and in other case I have even used parseInt like
for(var i = 0; i < allsortedValues.length; i++) {
allsortedValues[i] = parseInt(allsortedValues[i]);
}
before applying sort but in all cases result is same. Will some one guide what am I doing wrong?
You'll have to pass in a comparator function that converts the strings to numbers:
allsortedvalues = allsortedvalues.sort(function(a,b) {
return (+a) - (+b);
});
If there's a chance that some of your array entries aren't nicely-formatted numbers, then your comparator would have to get more complicated.
The construction (+a) involves the unary + operator, which doesn't do anything if a is already a number. However if a is not a number, the result of +a will be either the value of a when interpreted as a number, or else NaN. A string is interpreted as a number in the obvious way, by being examined and parsed as a string representation of a number. A boolean value would be converted as false -> 0 and true -> 1. The value null becomes 0, and undefined is NaN. Finally, an object reference is interpreted as a number via a call to its valueOf() function, or else NaN if that doesn't help.
It's equivalent to use the Number constructor, as in Number(a), if you like. It does exactly the same thing as +a. I'm a lazy typist.
If compareFunction is not supplied, elements are sorted by converting
them to strings and comparing strings in lexicographic ("dictionary"
or "telephone book," not numerical) order. For example, "80" comes
before "9" in lexicographic order, but in a numeric sort 9 comes
before 80.
To compare numbers instead of strings, the compare function can simply subtract b from a:
function compareNumbers(a, b)
{
return a - b;
}
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort
Related
I have two arrays one of it is having user id and another one is having user ids. Those arrays are as follows.
1)The array which is having user id.
data[key].effective_employees Which is eaqual to [2].
Now I have another array which is having numbers of employee ids which is as follows.
data2[0].id Which is eaqual to [2,22,21].
And now I am trying to see whether the array two has number in array 1 I am using the following logic to see whether it is working or not.
if ((/^\d+$/.test(_.intersection([data2[0].id.toString()], data[key].effective_employees)))) {
let isElem = _.contains(returnStackFilterd, value);
if (isElem == false) {
returnStackFilterd.push(value);
}
} else {
returnStackFilterd = _.without(returnStackFilterd, value);
}
But this is showing true for the number 2 if the array two is having 22. Psudo code of what is happening with it is as follows.
if([2]is in[22,21]){ it is printing true} I want false here as the number two is not in the second array. The second array contains 22 and 21 which is not eaqual to 2
How do i solve this problem? The above psudo code should print false.
Let's break down your test expression and see why it doesn't work.
First off, we know that data[key].effective_employees is [2]. data2[0].id might be [2, 22, 21] or [22, 21]. If I'm understanding your question correctly, you want the whole test expression to return true in the first case and false in the second case.
Rebuilding your test expression from the bottom up, the innermost expression we find is this:
data2[0].id.toString()
This is a string with the value '2,22,21' or '22,21', depending on which case we are talking about. Next, you wrap this string in an array:
[data2[0].id.toString()]
So now we have ['2,22,21'] or ['22,21']. Note the quotes; in either case, it is an array with a single element that is a string.
Next, you take the intersection of this array with data[key].effective_employees, which we know is [2]:
_.intersection([data2[0].id.toString()], data[key].effective_employees)
So this expression is effectively
_.intersection(['2,22,21'], [2])
or
_.intersection(['22,21'], [2])
You are always taking the intersection of two arrays, where the first contains a single string and the second contains a number. They can't have any elements in common, so that's always going to produce an empty array ([]).
Finally, you test whether that empty array matches a regular expression:
/^\d+$/.test(_.intersection([data2[0].id.toString()], data[key].effective_employees))
// is effectively the same as
/^\d+$/.test([])
Regular expressions are supposed to be matched against a string, not an array. JavaScript is very lenient in situations like these and will coerce the value you're passing to a string. That means that the value [] is first converted to the empty string '' before being matched to the regular expression /^\d+$/. The empty string does not contain any digits, so this test always returns false.
This is why your test doesn't work as intended. However, let's take a few steps back, because you seem to be doing many things you don't need to do. Why convert arrays to strings (and then back to array)? Why match against a regular expression, if you just want to know whether two arrays have elements in common?
The following, simpler expression will give you the elements that data[key].effective_employees and data2[0].id have in common:
_.intersection(data[key].effective_employees, data2[0].id)
This will evaluate to either [2] or [], depending on whether data[key].effective_employees contains the number 2 or not.
I suggest saving the result of this expression to a variable, because it makes your code easier to read. Let's call it commonIds:
const commonIds = _.intersection(data[key].effective_employees, data2[0].id)
Now you can formulate different conditions, based on what exactly you want this intersection to be like. My impression is that you just want it to be nonempty (i.e., at least one element in common). In that case, you can compare its length to zero:
if (commonIds.length > 0) {
// code for when there is an overlap
} else {
// code for when there is no overlap
}
As a final note, I recommend assigning your base expressions data[key].effective_employees and data2[0].id to variables as well. Again, this makes your code more readable, and it also ensures that you need to change only one line of code if those base expressions change. Putting it all together:
const key = 'x';
const data = { [key]: {
effective_employees: [2],
}};
const data2 = [{
id: [2, 22, 21],
}];
const userId = data[key].effective_employees;
const employeeIds = data2[0].id;
const commonIds = _.intersection(userId, employeeIds);
if (commonIds.length > 0) {
console.log('userId appears in employeeIds');
} else {
console.log('userId does not appear in employeeIds');
}
<script src="https://underscorejs.org/underscore-umd-min.js"></script>
If data[key].effective_employees is the number 2, and data2[0].id is the array [2, 22, 21], the expression to test whether data2[0].id contains data[key].effective_employees is:
data2[0].id.includes(data[key].effective_employees)
From your original question, data2[0].id.toString() coerces the array to a string 2,22,21, which is no use to you. You also do not need to use Underscore for this.
This question already has answers here:
How to sort an array of integers correctly
(32 answers)
Closed 2 years ago.
I am trying to sort a map using below function
var m=new Map();
m.set('0900','0910');
m.set('1100','1200');
m.set('1000','1030');
m.set('1235','1240');
var ma=new Map([...m.entries()].sort());
console.log(ma);
Output:{ 900 => 910, 1000 => 1030, 1100 => 1200, 1235 => 1240}
the map is getting sorted, but when I use the integers instead of characters I can't able to sort it
var m=new Map();
m.set(0900,0910);
m.set(1100,1200);
m.set(1000,1030);
m.set(1235,1240);
var ma=new Map([...m.entries()].sort());
console.log(ma)
Output:
{1000 => 1030, 1100 => 1200, 1235 => 1240, 900 => 910}
sort() function, when you don't supply a compareFunction as an argument, does not really work the way you instinctively expect it to work. See the following quote from relevant MDN page:
If compareFunction is not supplied, all non-undefined array elements
are sorted by converting them to strings and comparing strings in
UTF-16 code units order. For example, "banana" comes before "cherry".
In a numeric sort, 9 comes before 80, but because numbers are
converted to strings, "80" comes before "9" in the Unicode order. All
undefined elements are sorted to the end of the array.
The numeric sort bit in the quote explains why you're getting two different sorts with strings and numbers (with "0900" and 900). To overcome this, simply provide a function to the sort to the comparisons the way you want it, like so:
let ma = new Map([...m.entries()].sort((a, z) => a[0] - z[0]);
You can look into the details of how these compareFunctions work in the same MDN page: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Here, extract the first element with the help of destructuring out of the array and compare it.
var m=new Map();
m.set(0900,0910);
m.set(1100,1200);
m.set(1000,1030);
m.set(1235,1240);
var ma=new Map([...m.entries()].sort(([a], [b]) => a - b));
for(const e of ma) {
console.log(e);
}
MDN on Map.entries():
The entries() method returns a new Iterator object that contains the [key, value] pairs for each element in the Map object in insertion order.
When calling .sort() on the entries, it first converts the key-value pairs into strings before sorting them. That means that 0900 becomes 900, which comes after 1235, because '9' > '1' (first character of each string).
If you want to sort the entries by key, you will need to pass in a custom compareFunction argument to sort, which handles the key-value pairs and compares the keys as numbers:
var m = new Map();
m.set(0900,0910);
m.set(1100,1200);
m.set(1000,1030);
m.set(1235,1240);
var ma = new Map([...m.entries()].sort((kv1, kv2) => kv1[0] - kv2[0]));
console.log(ma);
var arr=[2,4,1,8,5];
var result=arr.sort(function compare(a,b)
{
return b-a;
});
document.writeln(result);
This is the example given to understand usage of JavaScript Array sort() method on javatpoint.com
in a simple word
sort function replace index based on return value
like
[1 5 3]
is (5 > 3) true so it is correct and goto next
(b-a) = 5-3 return a positive value [true]
(b-a) = 3-5 return a Negative value [false] it is not correct and must replaced with previous index
then sort function will do this in While loop until there is no negative value and return Array
In this case there was no need to use compare function. This function is useful when you want to compare objects which can not be compared by JavaScript using any operator or inbuilt functions.
You can find more details here - https://www.w3schools.com/js/js_array_sort.asp
Now the role of compare function here is that it compares two values - in this case numbers - and returns a number (0 means both numbers are equal, positive or negative number indicate greater than or less than relationship.
I have a value function which is passed into my orderBy as:
function getValue(item){
return [parseInt(item.approx_value_usd) || -1];
}
This definitely always returns a number array, but for some reason on the front-end AngularJS always orders my items by lexicographical order of the property 'approx_value_usd' e.g.
88 > 82 > 8 > 53 (wrong!)
I feel like I'm missing something but can't seem to get anywhere with this problem.
The return value of the "order-by" function is examined using simple comparisons. Your code is returning an array, not just a number. When an array appears in a JavaScript > or < comparison, it'll be converted to a string. That's done by taking the string value of each element in the array and joining them.
Thus, even though you were putting numbers in the array, when Angular actually used the returned value it ends up being a string anyway. If you drop the [ ] it should work.
This question already has answers here:
How to sort an array of integers correctly
(32 answers)
Closed 9 years ago.
In multiple browsers, the following code doesn't sort the numbers correctly:
a = new Array();
a.push(10);
a.push(60);
a.push(20);
a.push(30);
a.push(100);
document.write(a.sort())
It returns 10,100,20,30,60.
Anyone know why?
a.sort(function(a,b){return a - b})
These can be confusing.... check this link out.
I've tried different numbers, and it always acts as if the 0s aren't there and sorts the numbers correctly otherwise. Anyone know why?
You're getting a lexicographical sort (e.g. convert objects to strings, and sort them in dictionary order), which is the default sort behavior in Javascript:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort
array.sort([compareFunction])
Parameters
compareFunction
Specifies a function that defines the sort order. If omitted, the array is sorted lexicographically (in dictionary order) according to the string conversion of each element.
In the ECMAscript specification (the normative reference for the generic Javascript), ECMA-262, 3rd ed., section 15.4.4.11, the default sort order is lexicographical, although they don't come out and say it, instead giving the steps for a conceptual sort function that calls the given compare function if necessary, otherwise comparing the arguments when converted to strings:
13. If the argument comparefn is undefined, go to step 16.
14. Call comparefn with arguments x and y.
15. Return Result(14).
16. Call ToString(x).
17. Call ToString(y).
18. If Result(16) < Result(17), return −1.
19. If Result(16) > Result(17), return 1.
20. Return +0.
The default sort for arrays in Javascript is an alphabetical search. If you want a numerical sort, try something like this:
var a = [ 1, 100, 50, 2, 5];
a.sort(function(a,b) { return a - b; });
You can use a sort function :
var myarray=[25, 8, 7, 41]
myarray.sort( function(a,b) { return a - b; } );
// 7 8 25 41
Look at http://www.javascriptkit.com/javatutors/arraysort.shtml
try this:
a = new Array();
a.push(10);
a.push(60);
a.push(20);
a.push(30);
a.push(100);
a.sort(Test)
document.write(a);
function Test(a,b)
{
return a > b ? true : false;
}