Javascript sort help - javascript

I'm trying to sort some xml into different arrays and I'm a bit stuck on how to go about this.
Here is the xml: http://pastebin.ca/1754892
I'm using this xpath expression to get every "series" element that contains at least one "item" child node.
var ceerez = theXML.evaluate( '//series[item]' ,theXML, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
then I'm iterating over the result and putting the elements in a regular array:
var newArr=[];
for (var m = 0; m < ceerez.snapshotLength; m++){
newArr.push(ceerez.snapshotItem(m));
}
so what I would like to do next is to map and sort the elements in the newArr array into new arrays for each different sort.
I want to have one array that is numerically sorted by the "pub" attribute (as numbers) for each series element.
One array that is sorted alphabetically for each "title" child element's text.
One array that is sorted by date for each "item" child element.
I know how to do this with the sort() method, but I cant figure out how to do it from within the map() method so that I can make it into a new array.
var a2z1 = newArr.map(function(item){
item
.sort(function(a,b) {
return a.firstElementChild.textContent.toLowerCase().replace(/[^a-z,0-9]/gm, '') < b.firstElementChild.textContent.toLowerCase().replace(/[^a-z,0-9]/gm, '') ? -1 : 1;
});
);
(a.firstElementChild) would be the "title" element.

Make two other copies of the array (or three, if you don't want to use the original) and, using the sort method, sort each array (in place) by the criteria you specified.
Something like:
var copy1 = newArr.slice(0);
var copy2 = newArr.slice(0);
var copy3 = newArr.slice(0);
copy1.sort(function (a, b) {
// sort logic
});
copy2.sort(function (a, b) {
// sort logic
});
copy3.sort(function (a, b) {
// sort logic
});

Related

Keeping the order of insertion In Map object after deleting elements

My Findings:
object.forEach loop is messing up order of element (ascending and descending) but for loop is working fine. Does anyone else experienced it too ? or any explanation about it ? I think JavaScript does not guarantee property order of objects.
What I am trying to achieve ?
I have an array of type string which is sorted in descending order.
words: string[] = [];
words = this.getSomeStringArray();
word.sort();
word.reverse();
I have then passed this array to a function named countWordFrequency() as below.
private CountWordFrequency(words: string[]) : Map<string, number> {
let mapObject: Map<string, number> = new Map<string, number>();
for(var i=0; i < words.length; i++) {
!mapObject.has(words[i]) ? mapObject.set(words[i], 1) :
mapObject.set(words[i], mapObject.get(words[i]) + 1);
}
console.log(mapObject);
return mapObject;
}
I have used for loop here because forEach was messing again with the order of words array so with for loop i avoided it and performed insertion so that keys (string) are in descending order and number here presents how many times that word occurred in words array. After this I am calling this function which will first get values from the Map object in valueArray and then it sort in descending order and keep first 5 eliminating rest of them. Then in a forEeach on mapObject I am checking if the map element has value equals to that array keep it else delete it. to this it is fine but again in this operation that descending order of insertion is messed up. Here is the function.
private identifyTopFive(mapObject: Map<string, number>) : Map<string, number> {
let valueArray: number[] = [];
//Get all values from the map in array.
valueArray = Array.from(mapObject.values());
//Sort them in descending order.
valueArray.sort( (a,b)=> { return b-a });
//Delete duplicate values from array.
valueArray = valueArray.filter((element, index, self)=> {
return index == self.indexOf(element);
});
//Get only first 5 values in array and discard rest.
valueArray = valueArray.slice(0,5);
//Delete elements from the mapObject whose values who are not Top 5.
mapObject.forEach((key,value,mapObject) => {
if(!valueArray.includes(key))
mapObject.delete(value);
});
console.log(valueArray);
console.log(mapObject);
return null;
}
This there any technique to keep this descending order or any other data structure that I can use to keep the descending order of string values along with their occurrence.
Solved
The problem was with the data structures I have been using and not the forEach loop. I converted my map object to an array of objects and sorted it based upon the value in descending order, this worked for me.

Javascript/JQuery - Sort by split part of array?

I want to sort an array by a split part of an array.
example_array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"]
I want to so it sorts it like this:
console.log(code here) // prints ["Zebra:Add","Jam:Back","Pay:Cold","And:Vets"]
Note: I want "Zebra:Add","Pay:Cold", etc to stay together. I just want it be sorted by the text after the ":".
From your comment on the question:
I can't even think of a solution
Break the problem into smaller pieces. You want to sort an array by a part of the strings in the array, so you need to figure out / look into
How to sort an array (you've done that, you've found the sort method)
How to isolate the part of the string you want to sort on
How to correctly compare strings for Array#sort
How to do #2 and #3 within the context of doing #1
Re #2, there are various ways to do that. You could find the : via String#indexOf and then use substring to get all characters after it. You could split the string on :, then use the second half (if you know there won't be more than one : in the string). Or you could use a regular expression to isolate everything after the first :.
For instance, someString.match(/:.*$/)[0] isolates all characters starting with the first :. (Including the : is harmless, but you could use .substring(1) if you don't want to include it.)
Re #3: Array#sort expects its callback to return a negative number if the first argument should come before the second, 0 if their order doesn't matter, or a positive number if the second should come before the first. String#localeCompare compares strings according to the current locale and returns exactly that information, so we want to use that.
Re #4: Array#sort accepts a callback function, so you could do all the string splitting and comparison in that callback. But since the callback will be called repeatedly, frequently with either the first or second argument being one that's already been checked before, for larger arrays doing it then may be inefficient. It may make more sense to do all the string splitting / isolation in advance, then do the sort, then get your desired result.
So:
The not-particularly-efficient way (which is fine for data sets like your small array) is to isolate the part you want to sort on within the sort callback:
var array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array.sort(function(left, right) {
return left.match(/:.*$/)[0].localeCompare(right.match(/:.*$/)[0]);
});
var array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array.sort(function(left, right) {
return left.match(/:.*$/)[0].localeCompare(right.match(/:.*$/)[0]);
});
console.log(array);
With ES2015+ syntax:
const array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array.sort((left, right) =>
left.match(/:.*$/)[0].localeCompare(right.match(/:.*$/)[0])
);
const array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array.sort((left, right) =>
left.match(/:.*$/)[0].localeCompare(right.match(/:.*$/)[0])
);
console.log(array);
If it's a massive array where doing those splits on every compare is problematic, you could map first, then sort, then unmap:
var array = /*...really big array...*/;
array =
array.map(function(entry) { return {full: entry, key: entry.match(/:.*$/)[0]};})
.sort(function(left, right) { return left.key.localeCompare(right.key); })
.map(function(entry) { return entry.full; });
var array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array =
array.map(function(entry) { return {full: entry, key: entry.match(/:.*$/)[0]};})
.sort(function(left, right) { return left.key.localeCompare(right.key); })
.map(function(entry) { return entry.full; });
console.log(array);
With ES2015+ syntax:
let array = /*...really big array...*/;
array =
array.map(entry => ({full: entry, key: entry.match(/:.*$/)[0] }))
.sort((left, right) => left.key.localeCompare(right.key))
.map(entry => entry.full);
let array = ["Zebra:Add","Pay:Cold","And:Vets","Jam:Back"];
array =
array.map(entry => ({full: entry, key: entry.match(/:.*$/)[0] }))
.sort((left, right) => left.key.localeCompare(right.key))
.map(entry => entry.full);
console.log(array);
I like the simplicity of the previous answer, in comparison My approach is probably too wordy! But here goes...
1.) take the original array and build a new sorting array from it, JSON array with each object having a text1 and text2 value... we'll sort on the text 2 value
2.) run a sort based on the text2 value
3.) empty the original array
4.) loop over the sorting array and re-populate the original array
heres a fiddle example I threw together
// STARTING ARRAY. WE WANT TO SORT BY THE TEXT AFTER THE COLON
example_array = ["Zebra:Add", "Pay:Cold", "And:Vets", "Jam:Back"];
// AN EMPTY ARRAY TO BUILD A JSON ARRAY FROM, THE SORT FROM THE DESIRED TEXT STRING
sorting_array = [];
// LOOP THROUGH THE ORIGINAL ARRAY AND PUSH A NEW OBJECT TO THE SORTING ARRAY
// EACH OBJECT CONTAINS A TEXT1 VALUE AND A TEXT2 VALUE
$.each(example_array, function(i, val){
sorting_array.push({"text1": val.split(':')[0], "text2": val.split(':')[1]})
})
// SORT THE SORTING ARRAY BY THE TEXT2 VALUE
sorting_array.sort(function(a, b){
if (a.text2 < b.text2) return -1;
if (b.text2 < a.text2) return 1;
return 0;
});
// EMPTY OUR ORIGINAL ARRAY
example_array = [];
// FOR DEMO PURPOSES LETS DISPLAY EACH IN THE DOM IN A UL ,
// AND ALSO RE-POPULATE THE ORIGINAL ARRAY WITHT HE NEW ORDER
$.each(sorting_array, function(i, val){
example_array.push(val.text1+':'+val.text2)
})
// TO SHOW THE NEW ORDER, LETS LOOP BACK OVER THE EXAMPLE_ARRAY
$.each(example_array, function(i, val){
$('ul').append('<li>' + val+ '</li>');
})

Sort by values of properties on Object in JavaScript?

I have an object like this:
I would like to do two things.
Sort the properties based on their values
I would to know the order (or index) for any given property. For example, after ordering, I would like to know that the index of 00D is the 5th.
How can I achieve this in JavaScript?
While you can not sort properties of an object, you could use an array of keys of the object, sort them and take the wanted element, you want.
var keys = Object.keys(object), // get all keys
indices = Object.create(null); // hash table for indices
// sort by value of the object
keys.sort(function (a, b) { return object[a] - object[b]; });
// create hash table with indices
keys.forEach(function (k, i) { indices[k] = i; });
// access the 5th key
console.log(keys[5]);
// get index of 00G
console.log(indices['00G']);

Using setValues() with arrays of different lengths

I have a two-dimensional array in Google apps script that contains arrays of different lengths. I would like to set the values of the array in a spreadsheet. However, because the arrays inside it are different lengths, I receive an error that essentially says the range and the array height don't line up. I've listed an example of the structure of the array below.
I can make it work if I add empty values to each individual array so that they all match the length of the longest array. This seems like a workaround though. Is there another way that I can set the values of the two-dimensional array?
var array = [
[a],
[b,c],
[d,e],
[],
[f,g,h,i],
[],
[j,k],
]
No, you cannot. The dimensions must match.
What you can do if you have few "rows" with great length difference, is to set each row on it's own.
for( var i = 0; i < array.length; ++i )
sheet.getRange(i+1, 1, 1, array[i].length).setValues([array[i]]);
But that's just another workaround. But working on your array to make all lengths match and do a single setValues will probably perform better.
In case your real array has many rows, individual writes will be expensive. Redimensioning each row array is fairly straightforward due to the way js handles arrays. A pattern similar to one i use is:
function myFunction() {
var array = [
[1],
[2,2],
[3,5],
[],
[0,0,0,0],
[],
[0,0],
];
// get length of the longest row
var max = array
.slice(0)
.sort(function (a,b) {
return ( (a.length !== b.length) ? 1 : 0 );
})[0].length;
// arrays are zero indexed
var maxi = max-1;
// insert a pointer at max index if none exists
array = array
.map(function (a){
a[maxi] = a[maxi] || "";
return a;
});
Logger.log(array);
}

Parse data and order alphabetically under letter

This is what I would like to become:
This is my javascript:
var retrievedObject = localStorage.getItem('exhibitor');
// CALL FUNCTION
parsePerObject(JSON.parse(retrievedObject));
function parsePerObject(data){
}
This is my object in my localStorage :
{"41873":{"id":"41873","external_id":"","eventid":"5588","venueid":"0","exhibitorcategoryid":"0","name":"Niels
Vroman","shortname":"","booth":"","imageurl":"","mapid":"0","y1":"0","x1":"0","x2":"0","y2":"0","description":"Niels
uit Zulte.","tel":"0497841121","address":"Drogenboomstraat
54","email":"vroman.niels#hotmail.com","web":"http://nielsvroman.be","code":"","username":"","password":"","image1":"","imagedescription1":"","image2":"","imagedescription2":"","image3":"","imagedescription3":"","image4":"","imagedescription4":"","image5":"","imagedescription5":"","image6":"","imagedescription6":"","image7":"","imagedescription7":"","image8":"","imagedescription8":"","image9":"","imagedescription9":"","image10":"","imagedescription10":"","image11":"","imagedescription11":"","image12":"","imagedescription12":"","image13":"","imagedescription13":"","image14":"","imagedescription14":"","image15":"","imagedescription15":"","image16":"","imagedescription16":"","image17":"","imagedescription17":"","image18":"","imagedescription18":"","image19":"","imagedescription19":"","image20":"","imagedescription20":"","order":"0","brands":[],"categories":[],"linktodetails":true,"imagethumb":""},"41877":{"id":"41877","external_id":"","eventid":"5588","venueid":"0","exhibitorcategoryid":"0","name":"Ferdau
Daems","shortname":"","booth":"","imageurl":"","mapid":"0","y1":"0","x1":"0","x2":"0","y2":"0","description":"Ferdau
Daems","tel":"0497683697","address":"Waregem","email":"fer.dau#gmail.com","web":"http://ferdau.be","code":"","username":"","password":"","image1":"","imagedescription1":"","image2":"","imagedescription2":"","image3":"","imagedescription3":"","image4":"","imagedescription4":"","image5":"","imagedescription5":"","image6":"","imagedescription6":"","image7":"","imagedescription7":"","image8":"","imagedescription8":"","image9":"","imagedescription9":"","image10":"","imagedescription10":"","image11":"","imagedescription11":"","image12":"","imagedescription12":"","image13":"","imagedescription13":"","image14":"","imagedescription14":"","image15":"","imagedescription15":"","image16":"","imagedescription16":"","image17":"","imagedescription17":"","image18":"","imagedescription18":"","image19":"","imagedescription19":"","image20":"","imagedescription20":"","order":"0","brands":[],"categories":[],"linktodetails":true}}
Does anyone know how I can sort alphabetically on the name and make a header from the first letter?
Say you have an Array of objects, not an Object of objects, to enable indexing and sorting. Objects don't have order.
You retrieve it from localStorage. You parse it.
var people = JSON.parse(localStoarge.getItem("exhibitor");
// now you have an array of objects, each object representing a person.
// regardless of what structure you have now, change it to achieve this.
var comparePersons = function(a, b) {
// this function will compare two people objects.
return a.name.localeCompare(b.name);
// it's using String.prototype.localeCompare which returns 1 if a.name > b.name,
// 0 for equal and -1 for smaller. localeCompare is lexicographic comparison.
};
people.sort(comparePersons);
// now you have the people sorted alphabetically.
You can run through the people array, get the unique start letters, make an array of out them, and then display data as you want. It should be fairly simple.
var letters = '', groups = {};
for (var i = 0, len = people.length; i < len; i++) {
var letterKey = people[i].name.charAt(0).toLowerCase();// get the first letter
if (letters.indexOf(letterKey)) == -1) {
letters += letterKey;
groups[letterKey] = [people[i]];// index the people by unique letters.
} else {
groups[letterKey].push([people[i]]);// add to the existing list. Another Syntax fix
};
};
At this point you have an object like this:
a: [person1, person2, person5, etc..]//the people at A.
b: [person 3, person 4, etc..]// the people at B.
Just use the above data to create the display. Anything more and I would have to invoice you:).
The tricks here are Array.prototype.sort(here is more on it) and String.prototype.localeCompare(read more here).

Categories