How to sort JavaScript string array - javascript

I have the following array:
var arr = ["COL10","COL5",
"COL4","COL3",
"COL8","COL9",
"COL2","COL7",
"COL1","COL6"];
console.log("After sort:"+arr.sort());
The output is:
After sort:COL1,COL10,COL2,COL3,COL4,COL5,COL6,COL7,COL8,COL9
But I want it to be:
After sort:COL1,COL2,COL3,COL4,COL5,COL6,COL7,COL8,COL9,COL10
How should I do this?

Use the following approach with Array.sort and String.slice functions:
var arr = ["COL10","COL5","COL4","COL3","COL8","COL9","COL2","COL7","COL1","COL6"];
arr.sort(function (a,b) {
return a.slice(3) - b.slice(3);
});
console.log(arr);

You could split the items and sort the parts separate.
var arr = ["COL10", "COL5", "COL4", "COL3", "COL8", "COL9", "COL2", "COL7", "COL1", "COL6"];
arr.sort(function (a, b) {
var aa = a.split(/(\d+)/g),
bb = b.split(/(\d+)/g);
return aa[0].localeCompare(bb[0]) || aa[1] - bb[1];
});
console.log(arr);

Try out the alphanumerical sort from Brian Huisman:
Article
var arr = ["COL10", "COL5",
"COL4", "COL3",
"COL8", "COL9",
"COL2", "COL7",
"COL1", "COL6"
];
console.log("After sort:" + arr.sort(alphanum));
function alphanum(a, b) {
function chunkify(t) {
var tz = [],
x = 0,
y = -1,
n = 0,
i, j;
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i == 46 || (i >= 48 && i <= 57));
if (m !== n) {
tz[++y] = "";
n = m;
}
tz[y] += j;
}
return tz;
}
var aa = chunkify(a);
var bb = chunkify(b);
for (x = 0; aa[x] && bb[x]; x++) {
if (aa[x] !== bb[x]) {
var c = Number(aa[x]),
d = Number(bb[x]);
if (c == aa[x] && d == bb[x]) {
return c - d;
} else return (aa[x] > bb[x]) ? 1 : -1;
}
}
return aa.length - bb.length;
}

var arr = ["COL10","COL5",
"COL4","COL3",
"COL8","COL9",
"COL2","COL7",
"COL1","COL6"];
arr.sort(function(a,b) {
var a1 = parseInt(a.split('COL')[1]);
var b1 = parseInt(b.split('COL')[1]);
return a1 - b1;
});

Related

Sort array of objects of objects in javascript

I want to sort the below array by the "name" that is inside "user" object
var myArr = [
{"id":1,"user":{"name":"allen","id":101}},
{"id":2,"user":{"name":"martin","id":102}}
]
how can I do this?
I have a method to sort array of objects but I can't use it for array of objects of objects
this is the method:
function dynamicSort(property) {
var sortOrder = 1;
if (property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a, b) {
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
then I can sort using this:
myArr.sort(dynamicSort("id"));
I would create property as a getter function (For the complex examples. You could check if propFn is a function, use this below for the more complex ones. See this answer for checking is propFn is a function.):
var myArr = [
{"id":1,"user":{"name":"allen","id":101}},
{"id":2,"user":{"name":"martin","id":102}}
]
function dynamicSort(propFn, sortOrder = 1) {
return function (a, b) {
var result = (propFn(a) < propFn(b)) ? -1 : (propFn(a) > propFn(b)) ? 1 : 0;
return result * sortOrder;
}
}
console.log(myArr.sort(dynamicSort((obj) => obj.user.name)));
console.log(myArr.sort(dynamicSort((obj) => obj.user.name, -1)));
Alternatively, you can take a look at: Convert JavaScript string in dot notation into an object reference
This will give you an idea of how you can convert period notation into a nested object, but I recommend reading the disclaimer at the top.
To maintain backwards compatibility, you could use something like this below:
var myArr = [
{"id":1,"user":{"name":"allen","id":101}},
{"id":2,"user":{"name":"martin","id":102}}
]
function dynamicSort(propFn, sortOrder = 1) {
if (typeof propFn === "string") {
let prop = propFn;
if (prop[0] === "-") {
sortOrder = -1;
prop = prop.substr(1);
}
propFn = (obj) => obj[prop];
}
return function (a, b) {
var result = (propFn(a) < propFn(b)) ? -1 : (propFn(a) > propFn(b)) ? 1 : 0;
return result * sortOrder;
}
}
console.log(myArr.sort(dynamicSort((obj) => obj.user.name)));
console.log(myArr.sort(dynamicSort((obj) => obj.user.name, -1)));
console.log(myArr.sort(dynamicSort("id")));
console.log(myArr.sort(dynamicSort("-id")));
Edit:
If you are experiencing problems because of periods in your key names, this approach may be better suited as a solution. The path just has to either start as a bracket notation accessor or with a dot:
function dynamicSort(property, order) {
order||(order=1);
const getter = new Function("obj", "return obj" + property + ";");
return function(a, b) {
var result = (getter(a) < getter(b)) ? -1 : (getter(a) > getter(b)) ? 1 : 0;
return result * order;
}
}
var myArr = [{
"id": 1,
"user": {
"name": "allen",
"id": 101
}
},
{
"id": 2,
"user": {
"name": "martin",
"id": 102
}
},
{
"id": 3,
"user": {
"name": "barry",
"id": 103
}
}
]
console.log(JSON.stringify(myArr.sort(dynamicSort(".user.name"))));
Using the Object.byString() method from this answer, you can rewrite your function to take a path to the property you want to sort by:
var myArr = [
{"id":1,"user":{"name":"allen","id":101}},
{"id":2,"user":{"name":"martin","id":102}},
{"id":3,"user":{"name":"barry","id":103}}
]
console.log(JSON.stringify(myArr.sort(dynamicSort("user.name"))));
function dynamicSort(property) {
var sortOrder = 1;
if (property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a, b) {
var result = (byString(a, property) < byString(b, property)) ? -1 : (byString(a, property) > byString(b, property)) ? 1 : 0;
return result * sortOrder;
}
}
function byString(o, s) {
s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
s = s.replace(/^\./, ''); // strip a leading dot
var a = s.split('.');
for (var i = 0, n = a.length; i < n; ++i) {
var k = a[i];
if (k in o) {
o = o[k];
} else {
return;
}
}
return o;
}
I think it would be a little clearer and easier to use if you have the order as a second parameter, which means that your function should then more or less look like this:
function dynamicSort(property, order) {
return function(a, b) {
var result = (byString(a, property) < byString(b, property)) ? -1 : (byString(a, property) > byString(b, property)) ? 1 : 0;
return result * order;
}
}
You could use sort method but you first need to get nested property and for that you could pass a string and then use reduce method to get property.
var myArr = [{"id":2,"user":{"name":"martin","id":102}}, {"id":1,"user":{"name":"allen","id":101}}]
function dynamicSort(arr, prop) {
function getVal(obj, prop) {
return prop.split('.').reduce((r, e) => r[e] || {}, obj)
}
arr.sort((a, b) => {
let vA = getVal(a, prop);
let vB = getVal(b, prop);
return vA.localeCompare(vB)
})
}
dynamicSort(myArr, "user.name")
console.log(myArr)
Check out this SO answer for an answer to a fundamentally similar question.
Since the function in that answer is called differently than yours, with the array to be sorted passed in as a parameter, you could refactor it to be called in the same way as your existing dynamicSort function as follows:
function dynamicSort(property) {
var sortOrder = 1;
if (property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
var prop = property.split('.');
var len = prop.length;
return function (a, b) {
var i = 0;
while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; }
var result = (a < b) ? -1 : (a > b) ? 1 : 0;
return result * sortOrder;
}
}
You could then call it like so: myArr.sort(this.dynamicSort("user.name")).
Here is a working snippet to demonstrate:
function dynamicSort(property) {
var sortOrder = 1;
if (property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
var prop = property.split('.');
var len = prop.length;
return function (a, b) {
var i = 0;
while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; }
var result = (a < b) ? -1 : (a > b) ? 1 : 0;
return result * sortOrder;
}
}
var myArr = [
{"id":1,"user":{"name":"allen","id":101}},
{"id":2,"user":{"name":"martin","id":102}},
{"id":3,"user":{"name":"beth","id":103}},
];
console.log(myArr.sort(this.dynamicSort("user.name"))); //expected output: [{id:1, user:{name:"allen",...}}, {id:3, user:{name:"beth",...}}, {id:2, user:{name:"martin",...}}]
Try this out. Works fine for me
var sortedArray = myArr.sort((a, b) => {
const
nameA = a.user.name.toUpperCase(),
nameB = b.user.name.toUpperCase();
if(nameA < nameB)
return -1;
if(nameA > nameB)
return 1;
return 0;
});
myArr.sort(function(a, b) {
return a.user.name.localeCompare(b.user.name);
});

Sort one array according to the other array using quick sort in javascript

I want to sort a, according to ascending order of c. c gets sorted by this method, but a doesn't, a has only four unsorted elements at the end of code. What changes should I make?
var a = ['e','b','d','a','f','g','c'];
function quick_Sort(origArray,a) {
var i;
var length = origArray.length;
if (origArray.length <= 1) {
return [origArray, a];
} else {
var left = [];
var right = [];
var left1 = [];
var right1 = [];
var newArray = [];
var newArray1 = [];
var pivot = origArray.pop();
var pivot1 = a.pop();
for (i = 0; i < length-1; i++) {
if (origArray[i] <= pivot) {
left.push(origArray[i]);
left1.push(a[i]);
} else {
right.push(origArray[i]);
right1.push(a[i]);
}
}
return [newArray.concat((quick_Sort(left, left1)[0]), pivot, (quick_Sort(right, right1)[0])),newArray1.concat((quick_Sort(left, left1)[1]), pivot1, (quick_Sort(right, right1)[1]))];
}
}
var c = [3, 0, 2, 5, -1, 4, 1 ];
console.log("Original array: " + c);
console.log("Original array: " + a);
var e = quick_Sort(c,a);
c = e[0];
a = e[1];
console.log("Sorted array: " + c);
console.log("Sorted array: " + a);
If you want to sort a from the corresponding value of c you can:
var a = ['e','b','d','a','f','g','c'];
var c = [3, 0, 2, 5, -1, 4, 1 ];
var [sortedA, sortedC] = a.map((v,i) => [ v, c[i] ] ) //Pair the a and c
.sort((x,y)=>x[1] - y[1]) //Sort the array based on the c value
.reduce((c,v) => {
c[0].push( v[0] );
c[1].push( v[1] );
return c;
}, [[],[]]); //Seperate the a and c
console.log( sortedA );
console.log( sortedC );

sorting string function by custom alphabet javascript

Trying to sort an array of strings based on a custom alphabet. Probably some unnecessary code in there, but that was a couple different iterations mixed into one.
I am doing a base sort of the first letters, and if that doesn't work, I call the deep sort function and start working down the letters. But the result is only sorted by first letter, and the latter sorting seems to be arbitrary.
Any help?
var wordArray = ['apple', 'abbot', 'aatrophy', 'banana', 'berry', 'cherrypie', 'cherry', 'candy', 'grapefruit', 'pear', 'pizza', 'zebra', 'cigarette', 'guitar'];
var wordToLetterArray = [];
// var sortingString = "kwfhjrsbdtqmxaopzvieulgcny";
var sortingString = "abcdefghijklmnopqrstuvwxyz";
var deepSort = function(wordArray1, wordArray2) {
var forLoopIterations = 0;
if (wordArray1 && wordArray2) {
if (wordArray1.length > wordArray2.length) {
forLoopIterations = wordArray2.length;
} else {
forLoopIterations = wordArray1.length;
}
for (var i = 0; i <= forLoopIterations; i++) {
if (sortingString.indexOf(wordArray1[i]) > sortingString.indexOf(wordArray2[i])) {
return -1;
} else if (sortingString.indexOf(wordArray1[i]) < sortingString.indexOf(wordArray2[i])) {
return 1
} else {
if (i >= forLoopIterations) {
if (wordArray1.length > wordArray2.length) {
return 1;
} else if (wordArray1.length < wordArray2.length) {
return -1
} else {
return 0
}
} else {
}
}
};
} else {
return 0;
}
}
var populateWordToLetterArray = function() {
for (var i = 0; i <= wordArray.length - 1; i++) {
wordToLetterArray.push([]);
for (var x = 0; x <= wordArray[i].length - 1; x++) {
wordToLetterArray[i].push(wordArray[i][x]);
};
};
sortWordArraybyFirstLetter();
}
var sortWordArraybyFirstLetter = function sortWordArraybyFirstLetter() {
wordArray.sort(function(a, b) {
var aIndex = sortingString.indexOf(a[0]);
var bIndex = sortingString.indexOf(b[0]);
if (aIndex > bIndex) {
return 1;
} else if (aIndex < bIndex) {
return -1;
} else {
return deepSort(wordToLetterArray[wordArray.indexOf(a)], wordToLetterArray[wordArray.indexOf(b)]);
}
})
}
populateWordToLetterArray();
console.log(wordArray);
console.log(wordToLetterArray);
Make a function that "translates" a word into your custom alphabet and then sort the words by comparing their "translations":
function translate(str, alphabet) {
var abc = "abcdefghijklmnopqrstuvwxyz";
return [].map.call(str, function(c) {
return alphabet[abc.indexOf(c)] || c;
}).join("");
}
var wordArray = ['apple', 'abbot', 'aatrophy', 'banana', 'berry', 'cherrypie', 'cherry', 'candy', 'grapefruit', 'pear', 'pizza', 'zebra', 'cigarette', 'guitar'];
var sortingString = "kwfhjrsbdtqmxaozpvieulgcny";
wordArray.sort(function(a, b) {
return translate(a, sortingString).localeCompare(translate(b, sortingString));
});
document.write(wordArray)
This isn't particularly efficient, but there's room for optimizations.
It's very difficult to reason about code when you're nesting that deep. What you need is a clean way of producing a function to compare two strings based on your sort order. Once you have that, everything gets simpler.
The following should work for that:
function makeComparer(order) {
var ap = Array.prototype;
// mapping from character -> precedence
var orderMap = {},
max = order.length + 2;
ap.forEach.call(order, function(char, idx) {
orderMap[char] = idx + 1;
});
function compareChars(l, r) {
var lOrder = orderMap[l] || max,
rOrder = orderMap[r] || max;
return lOrder - rOrder;
}
function compareStrings(l, r) {
var minLength = Math.min(l.length, r.length);
var result = ap.reduce.call(l.substring(0, minLength), function (prev, _, i) {
return prev || compareChars(l[i], r[i]);
}, 0);
return result || (l.length - r.length);
}
return compareStrings;
}
var comparer = makeComparer('abcdefghijklmnopqrstuvwxyz');
console.log(comparer('apple', 'abbot'));
console.log(comparer('abbot', 'apple'));
console.log(comparer('apple', 'apple'));
console.log(comparer('apple', 'apple pie'));
console.log(comparer('apple pie', 'apple'));
Once you have that, sorting is as simple as using the built-in sort method:
var comparer = makeComparer('abcdefghijklmnopqrstuvwxyz');
var wordArray = ['apple', 'abbot', 'aatrophy', 'banana',
'berry', 'cherrypie','cherry', 'candy',
'grapefruit', 'pear', 'pizza', 'zebra',
'cigarette', 'guitar'];
wordArray.sort(comparer);
Full solution:
function makeComparer(order) {
var ap = Array.prototype;
// mapping from character -> precedence
var orderMap = {},
max = order.length + 2;
ap.forEach.call(order, function(char, idx) {
orderMap[char] = idx + 1;
});
function compareChars(l, r) {
var lOrder = orderMap[l] || max,
rOrder = orderMap[r] || max;
return lOrder - rOrder;
}
function compareStrings(l, r) {
var minLength = Math.min(l.length, r.length);
var result = ap.reduce.call(l.substring(0, minLength), function (prev, _, i) {
return prev || compareChars(l[i], r[i]);
}, 0);
return result || (l.length - r.length);
}
return compareStrings;
}
var wordArray = ['apple', 'abbot', 'aatrophy', 'banana',
'berry', 'cherrypie','cherry', 'candy',
'grapefruit', 'pear', 'pizza', 'zebra',
'cigarette', 'guitar'];
var comparer = makeComparer('abcdefghijklmnopqrstuvwxyz');
console.log(wordArray.slice().sort(comparer));
var weirdComparer = makeComparer("kwfhjrsbdtqmxaopzvieulgcny");
console.log(wordArray.slice().sort(weirdComparer));

Array of String to an array of JSON objects

For Example:
var array = ['a','a','b','b','c','c','c','c','d','d','d','d','d','d'];
var ans = array.reduce(function(acc,curr){
if(typeof acc[curr] == 'undefined') {
acc[curr] = 1;
} else {
acc[curr] += 1;
}
return acc;
}, {});
will give me:
ans = {'a':'2','b':'2','c':'4','d':'6'}
But my goal is to get it in this format
ans = [{'word':'a','count':'2'},{'word':'b','count':'2'},{'word':'c','count':'4'},{'word':'d','count':'6'}]
Any help would be appreciated thanks.
You already have a concise data format however, if you must transform it into the more verbose version, try
var wordCount = [];
Object.keys(ans).forEach(function(word) {
wordCount.push({
word: word,
count: ans[word]
});
});
If you wanted an all-in-one solution, try this one...
var array = ['a','a','b','b','c','c','c','c','d','d','d','d','d','d'];
var ans = array.map(function(word) {
return { word: word, count: 1 };
}).reduce(function(p, c) {
for (var i = 0, l = p.length; i < l; i++) {
if (p[i].word === c.word) {
p[i].count += c.count;
return p;
}
}
p.push(c);
return p;
}, []);

javascript, compare arrays of different sizes

with two arrays of potentially different sizes, what is best way to see if they are the same as far as it goes
for example
var a1 = [ 1, 2, 3 ];
var a2 = [ 1, 2 ];
var a3 = [ 1, 3 ];
a1 == a2 => true;
a1 == a3 => false;
am positive this has been done thousands of times and the syntax is well memorized
What about this (I'll just demonstrate on a1 and a2 -> I presume you can make function out of this):
var min_val = min(a1.length, a2.length);
var equals = true;
for(i = 0; i < min_val; i++)
{
if(a1[i] != a2[i])
{
equals = false;
break;
}
}
The result will be in equals variable of course. If you want to make function out of this, just pass a1 and a2 as arguments and return equals.
function compareArraySeq(a, b) {
return a.slice(0, b.length).join(' ') == b.slice(0, a.length).join(' ');
}
function compareArraySeq(a1, a2) {
var i, l = Math.min(a1.length, a2.length);
for (i=0; i<l; i++) {
if (a1[i] !== a2[i]) return false;
}
return true;
}
[edit] based on Tomalaks comments I'd say JSON can come to the rescue.
So, again: here's an Array extension that does what [I suppose] you want to do:
function comparePartial(arr1,arr2){
var arr2 = this, l1 = arr1.length, l2 = arr2.length;
return ( l1<1 || l2<1
? false :
JSON.stringify(arr1.slice(0, l2)) ===
JSON.stringify(arr2.slice(0, l1))
);
}
Array.prototype.comparePartial =
Array.prototype.comparePartial || comparePartial;
//usage
var a1 = [ 1, 2, 3 ]
,a2 = [ 1, 2 ]
,a3 = [ 1, 3 ]
,a4 = ['','']
,a5 = ['','','']
,a6 = []
,a7 = ['bla','doh',1]
,a8 = ['bla','doh',1,'yeah','really']
,a9 = [1,3,5,'doh']
,a10= ['1','3','5','doh']
,a11= [{a:1,b:2},{c:3,d:4}]
,a12= [{a:1,b:2},{c:3,d:4},{e:5,f:6}]
console.log(
[ a1.comparePartial(a2)
,a2.comparePartial(a1)
,a1.comparePartial(a3)
,a4.comparePartial(a5)
,a5.comparePartial(a6)
,a1.comparePartial(a6)
,a8.comparePartial(a7)
,a10.comparePartial(a9) //=> 'type safe' comparison
,a11.comparePartial(a12) //=> can compare arrays of Objects
].join(' - ')
); //=> true - true - false - true - false - false - true - false - true
function prefixEqual(a, b) {
var prefixLength = a.length < b.length ? a.length : b.length;
for(var i = 0; i < prefixLength; i+=1)
if( a[i] != b[i] )
return false;
return true;
}
Make a loop checking one spot at a time.
I have made this:
var compare = function (a1, a2) {
var l = Math.min(a1.length, a2.length);
for (var i = 0; i < l; i++) {
if (a1[i] !== a2[i]) {
return false;
}
}
return true;
}
Now you can compare arrays like this:
var a = [0, 1, 2, 3];
var b = [0, 1, 2];
var c = [0, 1, 3];
compare(a, b); //true
compare(a, c); //false
Hope this works for you :)
Fiddle link: http://jsfiddle.net/8zbJj/1/
If your arrays are strings or numbers or booleans you can compare their String values.
function compareSimpleValues(a,b){
if(a.length>=b.length)return String(a).indexOf(String(b))===0;
return String(b).indexOf(String(a))===0;
}

Categories