I'm doing AJAX calls to get data from the last.fm API and decided to use JSON as return data type. So far, so good. The problem is this: I want to get the top tracks using the tag.getTopTags method from the API and it returns me a JSON that isn't sorted by popularity (even though they say it is).
So how do I sort this JSON by count property (that indicates popularity) once I have this in a variable in my code?
Here's a sample of the JSON (pardon the lack of formatting, this is from a link they give on their website). It goes like this: toptags has tag which contains an array of tags, which have name, count, etc...
Here's the method from my code that requests the top tracks (via GET with a PHP file that's on my web server - this is working fine):
var getTopTracks = function() {
$.getJSON(
settings.PHP_REQUEST_URL,
{
method: "tag.getTopTags",
api_key: settings.LASTFM_APIKEY,
format: "json",
callback: "?"
},
function(data) {
// treat data here
});
};
I know how to show the data and stuff, I'd just like to sort the data before I show it. Anyone know how to do this in a simple way?
You're going to want to use Array's built-in sort method with a comparator function passed in. In your case:
data.toptags.tag.sort(function (t1, t2) {
return t1.count - t2.count;
});
The code is pretty self-explanatory, but the way it works is by using the regular sort function provided by the Array prototype and comparing the elements within the array by the comparison function provided. So, when it does comparison checks (like is count1 > than count2?), it will instead get an object in this case and you'll specify that the difference between one tag's count and the other should give precedence to which "ranks" higher in comparison.
Related
I have a design annoyance with some existing code in JS. The code is working, so I have no desperate hurry to change it, but the duplication shown below does annoy me. What is the usual/recommended/official way of avoiding this situation?
The actual system is a large/complex financial system, so I have simplified it to the most basic example which demonstrates the problem:
var colours={
red:{id:"red", vals:[1,0,0]},
green:{id:"green", vals:[0,1,0]},
grey:{id:"grey", vals:[0.5,0.5,0.5]}
// ...etc
};
// id needs to be known internally within the object - thus it is defined as a property.
// e.g:
colour.prototype.identify(console.log(this.id));
// id also needs to be used externally to find an object quickly.
// e.g:
function getcolour(s){return colours[s];}
// Although this works. It does mean duplicating data, with the theoretical possibility of a mismatch:
var colours={//...
blue:{id:"green", // oh dear...
How would this normally be handled by the experts?
This question is somewhat subjective.
When creating my applications I typically try do do the following:
never define same data in multiple places. source should always be unambiguous
if I need to create any indices for faster/easier access, I use utility methods to do it. Those methods should be properly unit-tested, so that I would have little doubts on them doing the wrong thing
use third party libraries as much as possible (such as already suggested lodash or underscore) to minimize the amount of code to be written/maintained.
If your algorithms and utilities are properly unit-tested you should not worry (too much) about getting the data into inconsistent state. However, if those are critically important systems/interfaces, you may add some validation on output. And it is generally a good practice to have data validation and marshaling on input.
Explanation on the utility methods:
if you have data array, say
var data = [{"id":"i_1", ...}, {"id":"i_2", ...},{"id":"i_3",....}];
Then and you have to create an index out of that or create more data sets based on the original array, then you create yourself a library of utility methods that do the modification on the array, create derivative data sets, or iterate on the array and create a resulting item on the fly. For example:
var createIndex = function( arr ){
// do something that converts the data array with expected structure to object
// {
// i_1: {"id":"i_1", ...},
// i_2: {"id":"i_2", ...},
// i_3: {"id":"i_3", ...}
return newObj;
}
This method will create a hash-map to access your data, which is faster then to iterate over the original array all the time. But now, this method you can easily unit-test and be sure that when you use it on the source data to get your intended dataset, there will be no inconsistency.
I wouldn't change the colours[key] direct access with other method to avoid duplication.
Any other attempt will lead to processing and you have mentioned that you have a large amount of data.
I assume that the duplication is over the incoming data that is a waste.
An example of processing over the network data consuming could be, going over the map object and set the id dynamically according to the key. (processing vs traffic)
colours[key].id = key
You can filter your object converting it to an array of objects and then filtering unique values. Converting it to an array would allow you to perform a lot of operations quicker and easier.
So you can map your object to an array:
var coloursArray = myObj.map(function(value, index) {
return [value];
});
Remove duplicates:
function removeDuplicates() {
return coloursArray.filter((obj, pos, arr) => {
return arr.map(mapObj => mapObj[id]).indexOf(obj[id]) === pos;
});
}
You can remove duplicates from an array using for example underscore.js through the .uniq method:
var uniqueColoursArray = _.uniq(coloursArray , function(c){ return c.id; });
Moreover, this function is pretty useless because you can access your element directly:
function getcolour(s){return colours[s];}
Calling colours[s] it is also shorter than getcolour(s). Your function would make sense if you pass also the array because it is not accessible in some other scope.
Then I can't understand why you do pass a console.log as parameter here:
colour.prototype.identify(console.log(this.id));
maybe you would like to pass just the this.id
Before I describe the issue, please forgive any incorrect terms and accidental references to objects instead of arrays and vice-versa, I'm not completely up to speed on this but working my way through it.
I have the following array in PHP saved as a session variable:
{"CategoryF":[],"CategoryA":["Life","There","People","Land","Family"],"CategoryC":["Various"]}
After a thumbnail in a grid of images is dragged into a new order, it execute a function in javascript and makes a call to a PHP script using ajax. It currently only retrieves the most up to date version of a session array. It will later progress to make the necessary steps to save the updated array back to session variable and database:
var sorty = Sortable.create(thumbcontainer, {
animation: 250,
draggable: "img",
dataIdAttr: 'id',
onUpdate: function (/**Event*/evt) {
var orderList = sorty.toArray();
var catsArray =
$.ajax({
type: 'POST',
url: 'includes/proc_cats.php',
dataType: 'json'
}).done(function(returnedCatsArray) {
console.log(returnedCatsArray);
});
console.log('Dragged. Order is: ' + orderList);
}
});
proc_cats.php
<?php
// Access the existing session
session_start();
// $catsArray is a session variable, in the format as above.
$catsArray = json_encode($_SESSION['categoriesPics']);
echo $catsArray;
?>
The var orderList will produce a string with the order of each thumbnail by id, separated by comma: '42,35,95,12,57'.
The console shows the PHP array as a javascript array fine but in a different order. I want to be able to insert the string containing the orders into the array and save it back into the database. It will associate with its relevant category, similar to:
{"CategoryF":[],"CategoryA":["Life":["23,74,47,12,86,83,12"],"There","People","Land","Family"],"CategoryC":["Various"]}
But can't lose the order as other parts of the site reference the array by indices using array_keys. The console produces:
Object:
CategoryA:Array[0]
CategoryC:Array[0]
CategoryF:Array[5]
Have I missed something? I believe that the overall array is an object rather than an array because it didn't have any index whereas the subcategories did and they get presented as an array. array_keys in PHP have made it straightforward enough to work around any indexing problems up until now on the PHP side in other areas of the site but I'm wondering if the solution for the javascript side is something as straightforward? The subcategories currently have indices only because I've yet to associate and orderList with them so I'm not trying not to backtrack and build an index for the array as it's going to get difficult (unless there's a simple way to do this that I've overlooked).
(This is a more specific version of a question I asked an hour ago that I've now deleted for being too broad).
I believe you have a slight confusion based on the terms 'associative array' and 'array'. A php associative array corresponds to a javascript object. returnedCatsArray should be accessed similar to $catsArray. ie. with keys. If one of those keys returns an an actual array, you can then index into it.
php array_keys would be Object.keys(returnedCatsArray) in javascript.
From further research it appears this is just not doable. So the best way to do this may be to provide an order array alongside my category array.
If I add the additional code of:
$parentCatOrder = array_keys($catsArray);
in my proc_cats.php script I have a concise way of generating an index reference for my original array on the fly each time. This produces an array similar to:
$parentCatOrder = {'categoryF', 'categoryA', 'categoryC'};
which has an index that I can refer to that keeps its order. So $parentCatOrder[2] will always produce 'categoryC' unless I've changed the array myself.
I then return both arrays to javascript using the following:
$return_data['catsarray'] = $catsArray;
$return_data['parentcatsorder'] = $parentCatOrder;
// Encode it back into a JSON object before sending
echo json_encode($return_data);
In javascript I can reference returnedCatsArray.catsarray[returnedCatsArray.parentcatsorder[1]][3] if I'm working with an index of 1-3 and guarantee this will produce the same result for every user unless the array has been changed by the user.
I have inherited some code that uses the Play! framework which has scala.html files that have javascript in them. Play! and scala are all new to me.
One of the javascript functions does a post and gets back a JSON object. It then loops through the JSON object and creates an array.
var myArray = [];
function createArray(){
$.post('/createArray', $('#arrayForm').serialize()).done(function( data ) {
var obj1 = JSON.parse(data);
$.each(obj1, function(idx, obj) {
myArray.push(obj.name);
});
});
return true;
}
It then uses this array (of strings) to create a text input field that does autocomplete using the data in the array.
I want/need to convert this text input to a select dropdown using the Play! #select but the options arg for #select wants a List object (or Map or Seq - just figured List would be easier since I already have an array of strings).
If I manually create the List object, it works fine.
#select(pForm("equipName"), options(scala.collection.immutable.List("Yes","No")))
The problem is I cannot figure out how to convert the myArray array to a List object which I can then pass to the #select options.
I have found a lot of posts that talk about converting a scala List to an array but can't find a way to go the other way. I am hoping it is an easy thing that I can't seem to figure out.
Thanks in advance for the help.
You can not do that. And more precisely - you do not want to do that.
So basically your play application run on server. In your Play application all those .scala html files are compiled to generate some functions.
Now, when a play application receives a request from a client browser, it gets mapped to some controller by by router. The controller does some processing and finally take one of these above functions ( lets say for index.scala.html we get views.html.index ) and call this function with some parameters.
These functions returns some text which is then sent to the client's browser as HTTP response with response header Content-Type:text/html; charset=utf-8 which tells the browser to treat this text as html.
Now, the browser renders the html which has embedded JavaScript and hence runs the JavaScript. So... basically your JavaScrpt code does not exist on server... for play all of it is just text.
Both of these Scala code and JavaScript code are executed at very different times, at different computers and in different environments hence you can not do whatever you are saying.
I have an unusual problem to solve here. I have an array of Guids
[
"c01f8237-72c8-4fa6-9c53-1915750385aa",
"2c8a471b-c408-436c-81b1-3f3867d8ffb4",
"27a44d46-12bd-4784-ceed-57ada31b0e33"
]
This array has to be transformed into:
{
id: "c01f8237-72c8-4fa6-9c53-1915750385aa",
id: "2c8a471b-c408-436c-81b1-3f3867d8ffb4",
id: "27a44d46-12bd-4784-ceed-57ada31b0e33"
}
I know that shouldn't be done, but unfortunately cannot control the back end part. Any idea?
Thanks
The whole point of a dictionary key is that it uniquely maps to some value. Your desired output attempts to duplicate a key and therefore is neither possible nor does it make sense.
If you're passing this to a backend (as you suggest), then of course you can manually build a string to pass over the wire that duplicates keys in the payload, but you won't be able to actually do it in JavaScript first. You'll have to manually build the string.
Also note that you can call this format whatever you want, but you can't call it JSON and you can't use JSON libraries to build it (because it's not JSON). If your API expects a custom format, then you need to write code to build that custom format.
If all you want is a string just do something like
var str = '{' + idArray.map(function(id) {
return "id: "+id
}).join(',\n')+'}';
I have no idea what mime type you would put on that though since its not valid JSON.
I have a javascript application, that calls an api, and the api returns json. With the json, I select a specific object, and loop through that.
My code flow is something like this:
Service call -> GetResults
Loop through Results and build Page
The problem though, is sometimes that api returns only one result, so that means it returns an object instead of an array, so I cant loop through results. What would be the best way to go around this?
Should i convert my object, or single result to an arrary? Put/Push it inside an array? or should I do a typeof and check if the element is an array, then do the looping?
Thanks for the help.
//this is what is return when there are more than one results
var results = {
pages: [
{"pageNumber":204},
{"pageNumber":1024},
{"pageNumber":3012}
]
}
//this is what is returned when there is only one result
var results = {
pages: {"pageNumber": 105}
}
My code loops through results, just using a for loop, but it will create errors, since sometimes results is not an array. So again, do I check if its an array? Push results into a new array? What would be better. Thanks
If you have no control over the server side, you could do a simple check to make sure it's an array:
if (!(results.pages instanceof Array)) {
results.pages = [results.pages];
}
// Do your loop here.
Otherwise, this should ideally happen on the server; it should be part of the contract that the results can always be accessed in a similar fashion.
Arrange whatever you do to your objects inside the loop into a separate procedure and if you discover that the object is not an array, apply the procedure to it directly, otherwise, apply it multiple times to each element of that object:
function processPage(page) { /* do something to your page */ }
if (pages instanceof Array) pages.forEach(processPage);
else processPage(pages);
Obvious benefits of this approach as compared to the one, where you create a redundant array is that, well, you don't create a redundant array and you don't modify the data that you received. While at this stage it may not be important that the data is intact, in general it might cause you more troubles, when running integration and regression tests.