I have a simple array that I'm having the hardest time trying to sort. I'm thinking maybe it's because of the time format, so I'm unsure how to reference it or how I could sort the time, in this array format, so that I can sort it later.
//function created to input values
function put(key, value, obj) {
obj[key] = value;
return obj
}
//loads the document from ajax call
function loadDoc() {
//ajax call
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var data = xhttp.responseText;
//input data from webpage into dom element
document.getElementById('next').innerHTML = data
var test = document.getElementsByClassName('gridRow')
//create dict
var new_dict = {}
for(a=0;a<test.length;a++){
if(test[a].children[2].innerText == 'Ready') {
test[a].style.display = 'none';
//drops into the dictionary
put(String(test[a].children[0].innerText).replace(/\n/ig, ''),
test[a].children[3].innerText, new_dict)
}
}
document.getElementById('next').innerHTML = ''
//looping through the dict
for(var index in new_dict) {
document.getElementById('next').innerHTML += ("<br>" + index + " : " +
new_dict[index] + "<br>");
}
the output is the same order the names appear.
Whatever is creating new_dict is creating it incorrectly. It's an array, but the code creating it is using it like a plain object. I'd fix that so that it's, for instance, an array of objects.
But with your current structure:
If you want to loop through its properties in order alphabetically by the property names, you can use Object.keys to get the keys and sort it, then loop through the result via map creating the output:
document.getElementById('next').innerHTML = Object.keys(new_dict)
.sort((a, b) => a.localeCompare(b)) // Sorts lexicographically (loosely, "alphabetically")
.map(key => escapeHTML(key + ": " + new_dict[key]))
.join("<br>"); // Joins them with <br> in-between
}
...where escapeHTML encodes & and <, since you're generating HTML. A quick and dirty version (which is good enough for the above) would be something like:
// ONLY good enough to handle text that isn't in attributes
function escapeHTML(str) {
return str.replace(/&/g, "&").replace(/</g, "<");
}
Based on the way your array seems to be populated, and going for the simplist solution: why don't you just normalize the time value such that you have appropriately pre-pended 0s?
" john doe": "00:19:57"
" Guy Faux ": "00:36:40"
" Charles Sheen ": "01:35:37"
This is a dictionary, not an array. It would be more accurate to refer to the names as "keys" and not "indexes". In particular, the dictionary you have here maps names onto times. Anyway, one thing you could do is make a new dictionary that maps the times onto a list of names (as multiple names might have the same time). Then sort that dictionary's keys.
Use the following fix time formats :
function put(key, value, obj) {
obj[key] = value.replace(/(\b\d\b)/g,'0$1');
return obj;
}
then use:
Object.keys(new_dict)
.sort((a, b) => a.localeCompare(b))
.forEach(p=>document.getElementById('next').innerHTML +="<br>" + p + " : " +
new_dict[p] + "<br>");
Related
Hi there I have the following code:
function showsaveobj(){
let patient = creatobj();
let befaktoren = patient.addfaktoren();
console.log(befaktoren);
let show = document.getElementById("show");
show.innerHTML = "Vorname: " + patient.vorname + "<br>Nachname: " + patient.nachname + "<br>" + (function() {for (let entry of befaktoren.entries()){return entry}})();
};
This last function is invoked when I press save inside the html document. It creates an object with a surname and a lastname and it has a method which creates a map out of the values the user has entered into the form. The form has 24 values corresponding to the 24h of the day. So the map is 24 entries long. I want to print these entries into the html document as you can see above. It works fine with the name and the surname but when I use the for..of loop to write the single entries It only prints out the first entry of the map.
When I add
for (let x of befaktoren.entries()){console.log(x);}
The console shows me 24 Arrays with the key and the value inside. When I do the same thing inside the string with innerHtml it only writes the first array of the map into the document.
I am doing something wrong here, but i cannot figure out what. After searching the web for several days now i hope someone here can help me.
Thanks in advance
I think you misunderstood the Map.entries() method. entries() does not return an iterable object that you can traverse with a for loop, but instead it returns an Iterator that contains all the entries which you can then retrieve with the next() method.
see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
A Map itself is iterable so you can use your for loop on the map itself.
Despite that
your code:
someString + (function() {
for (let entry of befaktoren.entries()) {
return entry
}
})()
will always put the first element only into your string.
instead do something like this:
var befaktorenFormatter = function(input) {
let formattedString;
// directly iterate over the input iterable
for (let entry of input) {
formattedString += entry;
}
// don't return the current entry, return the fully formatted string instead
return formattedString;
}
show.innerHTML = "Vorname: " + patient.vorname + "<br>Nachname: " + patient.nachname + "<br>" + befaktorenFormatter(befaktoren);
Map has the convenience method forEach for iterating over its contents.
Also see: http://devdocs.io/javascript/global_objects/map/foreach .
Instead of using a for loop you could also do something like this:
let befaktoren = new Map([['foo', 'bar'], ['bar', 'foo']]);
let befaktorenFormatter = function(input) {
let formattedString;
input.forEach(function(value, key) {
formattedString += `${key}: ${value}<br>`;
});
return formattedString;
};
show.innerHTML = "Vorname: " + patient.vorname + "<br>Nachname: " + patient.nachname + "<br>" + befaktorenFormatter(befaktoren);
I hope that helped.
The json is quite large so I need to be able to filter the data by:
Name
country check severity (Critical, Warning, Ok)
and sort the data by:
name
created
modified
I created the json but I'm not sure how to filter them or sorting them.
JS:
$(document).ready(function () {
var showData = $('#results');
$.getJSON('screenings.json', function (data) {
console.log(data);
var results = data.results.map(function (item) {
return ' Created: ' + item.created + ' Modified: ' + item.modified + ' Name: ' + item.name + ': ' + item.country_check_unknown_severity;
});
showData.empty();
if (results.length) {
var content = '<li>' + results.join('</li><li>') + '</li>';
var list = $('<ul />').html(content);
showData.append(list);
}
});
showData.text('Loading the JSON file.');
});
$.getJSON('screenings.json', function (data) {
// 1 - Generate the objects
var results = data.results.map(function(item) {
var o = {};
o['Created'] = item.created;
o['Modified'] = item.modified;
o['Name'] = item.name;
o['CCUS'] = item.country_check_unknown_severity;
return o;
});
// 2 - Sort the objects
// the sort function (takes two object compares them depending on the key, and sort order)
function sortFN(key, ascendant, a, b) {
var num = ascendant? 1: -1;
if(a[key] < b[key]) return -num; // return negative if a less than b
if(a[key] > b[key]) return num; // return positive if b less than a
return 0; // return 0 if they are the same
}
results.sort(sortFN.bind(null, 'Name', true)); // call sort on objects (explaining bellow)
// 3 - Generate the strings (generate the strings in any form you want)
var strings = results.map(function(o){
var str = "";
str += "Name: " + o["Name"] + '<br>';
str += "Modified: " + o["Modified"] + '<br>';
str += "Created: " + o["Created"] + '<br>';
str += "CCUS: " + o["CCUS"] + '<br><br>';
return str;
})
// 4 - Show data (show the generated strings)
showData.empty();
if (strings.length) {
var content = '<li>' + strings.join('</li><li>') + '</li>';
var list = $('<ul />').html(content);
showData.append(list);
}
});
Explanation for the sort method: Array.prototype.sort takes a callback (function reference) that will pass to it two elements of the array. The callback then compare the two elements passed to it and return -1 if the first is less than the second, +1 if the second is less than the first or 0 if the two objects are the same. Now the usual call to sort would be results.sort(sortFN) but since sortFN expect 4 parameters instead of 2, we manage to do so using sortFN.bind. That way is flexible as you can sort the array using any key you want and in any order. So use this:
results.sort(sortFN.bind(null, 'Name', false)); // to sort the results array using the key ('Name') in the descending order (false)
// Or...
results.sort(sortFN.bind(null, 'Modified', true)); // to sort it using the key ('Modified') in the ascending order (true)
//...
Just note that the sorting of dates could be innacurate as it compares the string not the actual dates. If you want a more accurate way to do it create a function sortDatesFN and pass it to sort instead of sortFN.
Filtering:
// 1.5 - Filter objects (this is better be before the sort)
// the filter function (check if a string (value) exist inside the string (o[key])
function filterFN(key, value, o) {
var prop = o[key].toLowerCase();
return prop.indexOf(value.toLowerCase()) !== -1; // return true or false (true if prop includes value, false otherwise)
}
results = results.filter(filterFN.bind(null, "CCUS", "warning")); // will filter all objects that have warning in their CCUS property
// 2 - Sort goes here
...
Note that the filtering could be done mor than once. You could filter the result by Name, then for example filter the filtered reuslts again by CCUS.
filter takes a callback and give it every item of the array and store it in a new array if that callback returned true. To make filter more flexible (take three parameters instead of one), a .bind call is required (the same as for sort above). So use this:
results = results.filter(filterFN.bind(null, "CCUS", "warning")); // to filter just the object that have "warning" in their CCUS property
// OR...
results = results.filter(filterFN.bind(null, "Name", "s")); // to filter the object that have the character 's' in their Name property.
//...
This could be done using a regular expression (value will be then a regular expression) and instead of checking return prop.indexOf(valu..., it would be return value.test(prop);. (If you're familiar with regular expression of course. And it's won't be necessary for the need you mentioned. I just wanted you to know that it can be done in another way).
I think Im misunderstanding something here - I normally work in PHP and think I'm missing something small. My final array tmp is empty and displays as ",,,,,,,,,,,,,,,,". It seems to me my tmp array might be emptied somewhere or the scope gets reset for some reason. I'm using this as coordinates from a table where you can select table rows and posting to a webservice but my array seem to be erroneous.
var length = $("#arrayCount").html();
var letters = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
var col = getSelectedColumn(); //for example sake lets say "B" is the selected column
var row = getSelectedRow(); //selected rows will be from "11" - "16"
var columnIndexStart = letters.indexOf(col[0]);
var tmp = [];
for(var i = row[0]; i <= row[1]; i++) //rows[0] = 11 and rows[1] = 16
{
tmp[i] = [];
for(var j = columnIndexStart; j < letters.length; j++) //columns and starts at index 1 if we work with "B"
{
var val = $("#" + i + "_" + letters[j]).html(); //using the row and letters as the associated DOM elements ID. Easier to retrieve it's HTML then.
if(val != undefined)
{
console.log("Index [" + i + "]['" + letters[j] + "'] = " + val); //works perfectly and prints as it should.
tmp[i]['"'+letters[j]+'"'] = val; //using quotes to save letters? Is this preferred?
}
}
}
console.log('Final Array: ' + tmp); //empty??
console.log('Final Array: ' + tmp[14]['G']); //testing HTML output. But is undefined.
return tmp;
Any help will be greatly appreciated.
Edited:
Example of console output.
My final array tmp is empty and displays as ",,,,,,,,,,,,,,,,"
With non-numeric index you are setting the field of object and not the element for index.
If you will have two-dimensional numeric array with numeric indices like the following:
var tmp = [[1,2,3], [1,2,3]];
after console.log('tmp = ' + tmp); you will obviously get the output string like:
tmp = 1,2,3,1,2,3
Because when you are trying to convert array to string it converts it elements to string and represent them with a commas.
However when you are trying to set element with non-numeric index, you are setting the field of this object.
var tmp = [];
tmp['A'] = 123;
console.log("tmp = " + tmp); // tmp =
console.log(tmp.A); //123
So, console.log in your case works good - it is serializing all elements of two-dimensional array. But no one array of the second level does not have stored values, it has only fields, which are not included in the string representation of array.
You are getting a set of commas, because each sub-array of tmp array does not contains any element, so it's string representation is an empty string. Each sub-array contains the required data into it's fields.
When you are performing sum operation of string and object you are forcing object to convert to string representation. Instead of this it is recommended to use console.log(yourObj) - it will log the whole object without converting it to string.
//using quotes to save letters? Is this preferred?
No, "A" and A are different identifiers.
var s = new Object();
s['"A"'] = 123;
console.log(s['A']); //undefined
console.log(s['"A"']); //123
Additionally, if you will set fields with quotes - you can not get the field in normal style:
console.log(s."A"); //syntax error : expected identifier after '.'
You can also just do this (use comma, not plus):
console.log('Final Array: ', tmp); //empty??
console.log('Final Array: ', tmp[14]['G']);
I am currently trying to retrieve the corresponding dial_code by using the name which I am obtaining as a variable.
The application uses a map of the world. When the user hovers over a particular country, that country is obtained using 'getRegionName'. This is then used to alter the variable name. How can I use the variable name to retrieve the dial_code that it relates to?
JSON
var dialCodes = [
{"name":"China","dial_code":"+86","code":"CN"},
{"name":"Afghanistan","dial_code":"+93","code":"AF"}
];
The following code runs on mouse hover of a country
var countryName = map.getRegionName(code);
label.html(name + ' (' + code.toString() + ')<br>' + dialCodes[0][countryName].dial_code);
This code doesn't work correctly. The dialCodes[0][countryName].dial_code is the part that is causing the error, but I'm not sure how to correctly refer to the corresponding key/value pair
If you have to support old browsers:
Loop over the entries in the array and compare to the given name:
var dialCode;
for(var i = 0; i < dialCodes.length; i++) {
if(dialCodes[i].name === countryName) {
dialCode = dialCodes[i].dial_code;
break;
}
}
label.html(countryName + ' (' + dialCode + ')');
If you browser support Array.prototype.filter:
dialCodes.filter(function(e) { return e.name === 'China' })[0].dial_code
If you have control over it, I recommend making your object more like a dictionary, for example if you are always looking up by the code (CN or AF) you could avoid looping if you did this:
var dialCodes = {
CN: { "name":"China","dial_code":"+86","code":"CN" },
AF: {"name":"Afghanistan","dial_code":"+93","code":"AF"}
};
var code = dialCodes.CN.dial_code;
Or
var myCode = 'CN'; // for example
var code = dialCodes[myCode].dial_code;
Since it's an array you can use filter to extract the data you need.
function getData(type, val) {
return dialCodes.filter(function (el) {
return el[type] === val;
})[0];
}
getData('code', 'CN').dial_code; // +86
I wish to iterate over an object's properties and change them all to include "" around the value stored in them.
This object is passed to a REST call and the above format must be enforced. I prefer to handle the addition of "" in a central location, rather when assigning the actual values (the code is very complex and long).
I know that you can iterate through the object's properties easily:
$.each(queryOptions, function(obj){console.log(obj)})
However, can I somehow get reference to the actual property and set it from within the iteration?
Input:
queryOptions.value1 = 1234;
queryOptions.value2 = "testing";
queryOptions.value3 = 555;
Desired output:
queryOptions.value1 = "1234";
queryOptions.value2 = ""testing"";
queryOptions.value3 = "555";
Thanks
I agree with Pointy that this seems an odd requirement. But if it's really a requirement:
Using $.each:
$.each(queryOptions, function(key) {
queryOptions[key] = '"' + queryOptions[key] + '"';
});
Or just using JavaScript without any library stuff:
var key;
for (key in queryOptions) {
if (queryOptions.hasOwnProperty(key)) {
queryOptions[key] = '"' + queryOptions[key] + '"';
}
}