javascript sort with unicode - javascript

There are a lot of examples for sorting some JSON array by some property (i.e. 'title')
We are using compare function like this one:
function sortComparer(a, b) {
if (a.title == b.title)
return 0;
return a1 > b1 ? 1 : -1;
}
Problem is that Serbian Latin alphabet order looks like "A, B, C, Č, Ć, D,..."
When using sortComparer above I am getting D sorted before "Č" or "Ć".
Any idea how to sort respecting current culture language?

If the locale in your system is set correctly then you can use localeCompare method instead of greater-than operator to compare the strings - this method is locale aware.
function sortComparer(a,b){
return a.title.localeCompare(b.title)
};

For sorting an array with a custom setting do as following:
Create an array with a custom order of alphabets:
var alphabets = ["A", "B", "C", "Č", "Ć", "D","Dž","Đ","E","F","G","H","I","J","K","L","Lj","M","N","Nj","O","P","R","S", "ÛŒ","T","U","V","Z","Ž"];
Create a list of test array:
var testArrray = ["B2","D6","A1","Ć5","Č4","C3"];
Create a sort function name:
function OrderFunc(){
testArrray.sort(function (a, b) {
return CharCompare(a, b, 0);
});
}
create the CharCompare function(index: sort "AAAB" before "AAAC"):
function CharCompare(a, b, index) {
if (index == a.length || index == b.length)
return 0;
//toUpperCase: isn't case sensitive
var aChar = alphabets.indexOf(a.toUpperCase().charAt(index));
var bChar = alphabets.indexOf(b.toUpperCase().charAt(index));
if (aChar != bChar)
return aChar - bChar
else
return CharCompare(a,b,index+1)
}
Call OrderFunc for sorting the testArray(the result will be : A1,B2,C3,Č4,Ć5,D6).
Test Online
Good Luck

Use The Intl.Collator like you will get perfect sorting result
function letterSort(lang, letters) {
letters.sort(new Intl.Collator(lang).compare);
return letters;
}
console.log(letterSort('gu', ['છ','ક','ખ']));
// expected output: Array ["a", "ä", "z"]
console.log(letterSort('sv', ['a','z','ä']));
// expected output: Array ["a", "z", "ä"]
More detail you can check here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator

Related

Sort array of objects alphabetically by property with special characters [duplicate]

There are a lot of examples for sorting some JSON array by some property (i.e. 'title')
We are using compare function like this one:
function sortComparer(a, b) {
if (a.title == b.title)
return 0;
return a1 > b1 ? 1 : -1;
}
Problem is that Serbian Latin alphabet order looks like "A, B, C, Č, Ć, D,..."
When using sortComparer above I am getting D sorted before "Č" or "Ć".
Any idea how to sort respecting current culture language?
If the locale in your system is set correctly then you can use localeCompare method instead of greater-than operator to compare the strings - this method is locale aware.
function sortComparer(a,b){
return a.title.localeCompare(b.title)
};
For sorting an array with a custom setting do as following:
Create an array with a custom order of alphabets:
var alphabets = ["A", "B", "C", "Č", "Ć", "D","Dž","Đ","E","F","G","H","I","J","K","L","Lj","M","N","Nj","O","P","R","S", "ÛŒ","T","U","V","Z","Ž"];
Create a list of test array:
var testArrray = ["B2","D6","A1","Ć5","Č4","C3"];
Create a sort function name:
function OrderFunc(){
testArrray.sort(function (a, b) {
return CharCompare(a, b, 0);
});
}
create the CharCompare function(index: sort "AAAB" before "AAAC"):
function CharCompare(a, b, index) {
if (index == a.length || index == b.length)
return 0;
//toUpperCase: isn't case sensitive
var aChar = alphabets.indexOf(a.toUpperCase().charAt(index));
var bChar = alphabets.indexOf(b.toUpperCase().charAt(index));
if (aChar != bChar)
return aChar - bChar
else
return CharCompare(a,b,index+1)
}
Call OrderFunc for sorting the testArray(the result will be : A1,B2,C3,Č4,Ć5,D6).
Test Online
Good Luck
Use The Intl.Collator like you will get perfect sorting result
function letterSort(lang, letters) {
letters.sort(new Intl.Collator(lang).compare);
return letters;
}
console.log(letterSort('gu', ['છ','ક','ખ']));
// expected output: Array ["a", "ä", "z"]
console.log(letterSort('sv', ['a','z','ä']));
// expected output: Array ["a", "z", "ä"]
More detail you can check here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator

Sort JavaScript array with mixed characters

I am trying to sort an array of names into least to greatest order. Unfortunately JavaScript's .sort() will not work because it has underscores and letters in it.
I have this code:
var array = new Array("S1_FORM", "S2_FORM", "S3_2_FORM", "S3_FORM", "S3_3_FORM", "S4_FORM");
var SortedArray = array.sort();
This should sort it to be like:
S1_FORM, S2_FORM, S3_FORM, S3_2_FORM, S3_3_FORM, S4_FORM
Here's a jsdfiddle:
Your sort is a bit tricky since the _FORM keeps it from being just a straightforward lexicographical sort.
Try this:
var SortedArray = array.sort(function(a, b){
a = a.slice(0, -5);
b = b.slice(0, -5);
return a < b ? -1 : (a > b) ? 1 : 0;
});
I believe you want a custom sort comparison function. See this post:
How to define custom sort function in javascript?
As SHIELDHEAD suggested, you can pass a custom comparator function into Array.sort() when you want to sort by different rules than the default alphabetical/ordinal rules.
The format of the comparator function is as follows:
function(a,b){
// if a should be before b, return -1
// if b should be before a, return 1
// if they are equal, return 0
return a < b ? -1 : a > b ? 1 : 0;
}
In your case, I believe what your comparator function will need to do is grab the substring between "S" and "F" in your strings and compare those.
You can get that substring using regex: a = a.match(/(?!S)([0123456789_])+(?!F)/g);
Here's the working code:
var array = new Array("S1_FORM", "S2_FORM", "S3_2_FORM", "S3_FORM", "S3_3_FORM", "S4_FORM");
array.sort(function(a,b){
a = a.match(/(?!S)([0123456789_])+(?!F)/g);
b = b.match(/(?!S)([0123456789_])+(?!F)/g);
return a < b ? -1 : a === b ? 0 : 1;
});
document.getElementById("output").innerHTML = JSON.stringify(array);
<div id="output"/>
EDIT: Also note that the sort() function changes the original array, so you don't need to create a separate variable to store the sorted array.

what is the mechanism going on inside this sort function

i have gone through this article about Array.prototype.sort().Sort() function can behave differently according to the availability of compareFunction.For strings it does sorting using UNICODE value.But Here in this particular example an array contains two different elements having same first three letters.My question is how compareFunction decides which to go first in a situation like this??
var numbers = ['Hammer',"Hamburger"];
numbers.sort(function(a, b) {
return a - b;
});
console.log(numbers); //['Hammer','Hamburger']
I think you are getting problem because in compareFunction you are saying
a-b;
remember "str1"-"str2" will return a NaN. So you are not going to get expected results.
Say like bellow if you want to get it sorted in ascending order
a>b;
OR
a.localeCompare(b);
Full Code
var numbers = ['Hammer',"Hamburger"];
numbers.sort(function(a, b) {
return a.localeCompare(b);
});
console.log(numbers); //["Hamburger", "Hammer"]
This method does not apply for string values
To compare numbers instead of strings, the compare function can simply subtract b from a:
function compareNumbers(a, b) {
return a - b;
}
That being said, this should be used for numbers only and does not apply for strings.
Sorting non-ASCII characters
"For sorting strings with non-ASCII characters, i.e. strings with accented characters (e, é, è, a, ä, etc.), strings from languages other than English: use String.localeCompare. This function can compare those characters so they appear in the right order.:"
var items = ['réservé', 'premier', 'cliché', 'communiqué', 'café', 'adieu'];
items.sort(function (a, b) {
return a.localeCompare(b);
});
// items is ['adieu', 'café', 'cliché', 'communiqué', 'premier', 'réservé']
Otherwise, simply use the normal .sort() and don't worry about the implementation unless it appears odd to you
var fruit = ['apples', 'bananas', 'Cherries'];
fruit.sort(); // ['Cherries', 'apples', 'bananas'];
You can do like this with String array:
function compareString(a, b)
{
var lowera = a.toLowerCase();
var lowerb = b.toLowerCase();
if (lowera < lowerb){
return -1;
}else if (lowera > lowerb){
return 1;
}else{
return 0;
}
}
var numbers = ['Hammer',"Hamburger"];
numbers.sort(compareString);
console.log(numbers); //['Hamburger','Hammer']
.sort(function(){}) behaves like this (returned variables will be called result):
1) result < 0 - second element is bigger than first;
2) result = 0 - second element is equal to first element;
3) result > 0 - second element is smaller than first element;
So this algorithm only works for numbers, when comparing string, "str1" - "str2" will return NaN

can any one explain reduce function in javascripts

Can any one explain whats going on in this JavaScript code? I do not understand the part where the i.reduce is passed with [] as an initial value:
function longestString(i) {
// It will be an array like (['big',[0,1,2,3,4],'tiny'])
// and the function should return the longest string in the array
// This should flatten an array of arrays
var r = i.reduce(function(a, b) {
return a.concat(b);
}, []);
// This should fetch the longest in the flattened array
return r.reduce(function (a, b)
{
return a.length > b.length ? a : b;
});
}
The initial value in a reduce is an accumulator. If for example if i is [[1],[2],[3]] then the reduce statement is equivalent to:
r = [];
r = r.concat([1]);
r = r.concat([2]);
r = r.concat([3]);
In each step of the reduce the function must be called on two arguments. In the first step there must be some initial value. You can't call .concat on nothing so you start with an empty array.

Javascript array sort and unique

I have a JavaScript array like this:
var myData=['237','124','255','124','366','255'];
I need the array elements to be unique and sorted:
myData[0]='124';
myData[1]='237';
myData[2]='255';
myData[3]='366';
Even though the members of array look like integers, they're not integers, since I have already converted each to be string:
var myData[0]=num.toString();
//...and so on.
Is there any way to do all of these tasks in JavaScript?
This is actually very simple. It is much easier to find unique values, if the values are sorted first:
function sort_unique(arr) {
if (arr.length === 0) return arr;
arr = arr.sort(function (a, b) { return a*1 - b*1; });
var ret = [arr[0]];
for (var i = 1; i < arr.length; i++) { //Start loop at 1: arr[0] can never be a duplicate
if (arr[i-1] !== arr[i]) {
ret.push(arr[i]);
}
}
return ret;
}
console.log(sort_unique(['237','124','255','124','366','255']));
//["124", "237", "255", "366"]
You can now achieve the result in just one line of code.
Using new Set to reduce the array to unique set of values.
Apply the sort method after to order the string values.
var myData=['237','124','255','124','366','255']
var uniqueAndSorted = [...new Set(myData)].sort()
UPDATED for newer methods introduced in JavaScript since time of question.
This might be adequate in circumstances where you can't define the function in advance (like in a bookmarklet):
myData.sort().filter(function(el,i,a){return i===a.indexOf(el)})
Here's my (more modern) approach using Array.protoype.reduce():
[2, 1, 2, 3].reduce((a, x) => a.includes(x) ? a : [...a, x], []).sort()
// returns [1, 2, 3]
Edit: More performant version as pointed out in the comments:
arr.sort().filter((x, i, a) => !i || x != a[i-1])
function sort_unique(arr) {
return arr.sort().filter(function(el,i,a) {
return (i==a.indexOf(el));
});
}
How about:
array.sort().filter(function(elem, index, arr) {
return index == arr.length - 1 || arr[index + 1] != elem
})
This is similar to #loostro answer but instead of using indexOf which will reiterate the array for each element to verify that is the first found, it just checks that the next element is different than the current.
Try using an external library like underscore
var f = _.compose(_.uniq, function(array) {
return _.sortBy(array, _.identity);
});
var sortedUnique = f(array);
This relies on _.compose, _.uniq, _.sortBy, _.identity
See live example
What is it doing?
We want a function that takes an array and then returns a sorted array with the non-unique entries removed. This function needs to do two things, sorting and making the array unique.
This is a good job for composition, so we compose the unique & sort function together. _.uniq can just be applied on the array with one argument so it's just passed to _.compose
the _.sortBy function needs a sorting conditional functional. it expects a function that returns a value and the array will be sorted on that value. Since the value that we are ordering it by is the value in the array we can just pass the _.identity function.
We now have a composition of a function that (takes an array and returns a unique array) and a function that (takes an array and returns a sorted array, sorted by their values).
We simply apply the composition on the array and we have our uniquely sorted array.
This function doesn't fail for more than two duplicates values:
function unique(arr) {
var a = [];
var l = arr.length;
for(var i=0; i<l; i++) {
for(var j=i+1; j<l; j++) {
// If a[i] is found later in the array
if (arr[i] === arr[j])
j = ++i;
}
a.push(arr[i]);
}
return a;
};
Here is a simple one liner with O(N), no complicated loops necessary.
> Object.keys(['a', 'b', 'a'].reduce((l, r) => l[r] = l, {})).sort()
[ 'a', 'b' ]
Explanation
Original data set, assume its coming in from an external function
const data = ['a', 'b', 'a']
We want to group all the values onto an object as keys as the method of deduplication. So we use reduce with an object as the default value:
[].reduce(fn, {})
The next step is to create a reduce function which will put the values in the array onto the object. The end result is an object with a unique set of keys.
const reduced = data.reduce((l, r) => l[r] = l, {})
We set l[r] = l because in javascript the value of the assignment expression is returned when an assignment statement is used as an expression. l is the accumulator object and r is the key value. You can also use Object.assign(l, { [r]: (l[r] || 0) + 1 }) or something similar to get the count of each value if that was important to you.
Next we want to get the keys of that object
const keys = Object.keys(reduced)
Then simply use the built-in sort
console.log(keys.sort())
Which is the set of unique values of the original array, sorted
['a', 'b']
The solution in a more elegant way.
var myData=['237','124','255','124','366','255'];
console.log(Array.from(new Set(myData)).sort((a,b) => a - b));
I know the question is very old, but maybe someone will come in handy
A way to use a custom sort function
//func has to return 0 in the case in which they are equal
sort_unique = function(arr,func) {
func = func || function (a, b) {
return a*1 - b*1;
};
arr = arr.sort(func);
var ret = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (func(arr[i-1],arr[i]) != 0)
ret.push(arr[i]);
}
}
return ret;
}
Example: desc order for an array of objects
MyArray = sort_unique(MyArray , function(a,b){
return b.iterator_internal*1 - a.iterator_internal*1;
});
No redundant "return" array, no ECMA5 built-ins (I'm pretty sure!) and simple to read.
function removeDuplicates(target_array) {
target_array.sort();
var i = 0;
while(i < target_array.length) {
if(target_array[i] === target_array[i+1]) {
target_array.splice(i+1,1);
}
else {
i += 1;
}
}
return target_array;
}
I guess I'll post this answer for some variety. This technique for purging duplicates is something I picked up on for a project in Flash I'm currently working on about a month or so ago.
What you do is make an object and fill it with both a key and a value utilizing each array item. Since duplicate keys are discarded, duplicates are removed.
var nums = [1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10];
var newNums = purgeArray(nums);
function purgeArray(ar)
{
var obj = {};
var temp = [];
for(var i=0;i<ar.length;i++)
{
obj[ar[i]] = ar[i];
}
for (var item in obj)
{
temp.push(obj[item]);
}
return temp;
}
There's already 5 other answers, so I don't see a need to post a sorting function.
// Another way, that does not rearrange the original Array
// and spends a little less time handling duplicates.
function uniqueSort(arr, sortby){
var A1= arr.slice();
A1= typeof sortby== 'function'? A1.sort(sortby): A1.sort();
var last= A1.shift(), next, A2= [last];
while(A1.length){
next= A1.shift();
while(next=== last) next= A1.shift();
if(next!=undefined){
A2[A2.length]= next;
last= next;
}
}
return A2;
}
var myData= ['237','124','255','124','366','255','100','1000'];
uniqueSort(myData,function(a,b){return a-b})
// the ordinary sort() returns the same array as the number sort here,
// but some strings of digits do not sort so nicely numerical.
function sort() only is only good if your number has same digit, example:
var myData = ["3","11","1","2"]
will return;
var myData = ["1","11","2","3"]
and here improvement for function from mrmonkington
myData.sort().sort(function(a,b){return a - b;}).filter(function(el,i,a){if(i==a.indexOf(el) & el.length>0)return 1;return 0;})
the above function will also delete empty array and you can checkout the demo below
http://jsbin.com/ahojip/2/edit
O[N^2] solutions are bad, especially when the data is already sorted, there is no need to do two nested loops for removing duplicates. One loop and comparing to the previous element will work great.
A simple solution with O[] of sort() would suffice. My solution is:
function sortUnique(arr, compareFunction) {
let sorted = arr.sort(compareFunction);
let result = sorted.filter(compareFunction
? function(val, i, a) { return (i == 0 || compareFunction(a[i-1], val) != 0); }
: function(val, i, a) { return (i == 0 || a[i-1] !== val); }
);
return result;
}
BTW, can do something like this to have Array.sortUnique() method:
Array.prototype.sortUnique = function(compareFunction) {return sortUnique(this, compareFunction); }
Furthermore, sort() could be modified to remove second element if compare() function returns 0 (equal elements), though that code can become messy (need to revise loop boundaries in the flight). Besides, I stay away from making my own sort() functions in interpreted languages, since it will most certainly degrade the performance. So this addition is for the ECMA 2019+ consideration.
The fastest and simpleness way to do this task.
const N = Math.pow(8, 8)
let data = Array.from({length: N}, () => Math.floor(Math.random() * N))
let newData = {}
let len = data.length
// the magic
while (len--) {
newData[data[len]] = true
}
var array = [2,5,4,2,5,9,4,2,6,9,0,5,4,7,8];
var unique_array = [...new Set(array)]; // [ 2, 5, 4, 9, 6, 0, 7, 8 ]
var uniqueWithSorted = unique_array.sort();
console.log(uniqueWithSorted);
output = [ 0, 2, 4, 5, 6, 7, 8, 9 ]
Here, we used only Set for removing duplicity from the array and then used sort for sorting array in ascending order.
I'm afraid you can't combine these functions, ie. you gotta do something like this:-
myData.unique().sort();
Alternatively you can implement a kind of sortedset (as available in other languages) - which carries both the notion of sorting and removing duplicates, as you require.
Hope this helps.
References:-
Array.sort
Array.unique

Categories

Resources