Related
Hoping someone can help me out here or at least point me in the right direction. I have spent hours trying to get this sorted and I am lost.
The code below is just mock, my actual json is returned via AJAX using jquery. My problem is not sorting, but sorting on a nested json object.
I am trying to sort the json output based on cost. (lowest cost to highest), my attempts have failed and I cannot get this sorted. I keep getting "sort" is undefined.
Any help would be appreciated or if you can just point out what I am doing wrong here.
var json = '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
/*
This doesnt work and returns undefined.
json["shipping_method"]["quote"].sort(function(a, b) {
return a['cost'] > b['cost'];
});
// I found this example, but also didn't work.
custSort = (prop1, prop2 = null, direction = 'asc') => (e1, e2) => {
const a = prop2 ? e1[prop1][prop2] : e1[prop1],
b = prop2 ? e2[prop1][prop2] : e2[prop1],
sortOrder = direction === "asc" ? 1 : -1
return (a < b) ? -sortOrder : (a > b) ? //sortOrder : 0;
};
json.sort(custSort("quote", "cost", "desc"));*/
json = JSON.parse(json);
for (var i in json["shipping_method"]) {
// EDIT:: I want the sorting to occur here if possible.
for (j in json["shipping_method"][i]["quote"]) {
//EDIT:: I want to keep this for loop, but with the results sorted by cost
console.log(json["shipping_method"][i]["quote"][j]["cost"]);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Convert Object to Sorted Array
The object can be flattened out so that parent keys are included in the deep object as it's been iterated over. An early example to that can be found in this answers edit history. It has been removed since information like the quote-id was not deemed important.
Below is an example of using Object.values, which traverses an object and only returns an array of that objects values (discarding the keys). The values can then be sorted as intended, by cost.
const json = JSON.parse(getData());
for (let method in json["shipping_method"]) {
// cache
let quotes = json['shipping_method'][method]['quote']
// convert object to array and sort
let sortedQuotes = Object.values(quotes).sort((a, b)=>a.cost-b.cost);
console.log(sortedQuotes)
}
/* Dummy Data */
function getData() {
return '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
}
.as-console-wrapper {
max-height: 100vh !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Quotes by Cost per Shipping Method
This assumes that the quote ID is needed (perhaps to be placed on a row); otherwise this can be simplified using Object.values in place of Object.entries (amongst other changes).
Disregard what the output function is doing. It is a quick example, that doesn't ensure proper cell order and has a host of other limitations and vulnerabilities. It is only used to demonstrate that the original quote data is still available after sorting.
const data = JSON.parse(getData());
for (let method in data.shipping_method) {
output({row: method}, {class:'capitalize'})
// cache
let quotes = data.shipping_method[method].quote
let sortContent = Object.entries(quotes);
let sortedQuotes = sortContent.sort((a,b)=>a[1].cost-b[1].cost).map(i=>i[0]);
for (let quoteId of sortedQuotes){
let quoteInfo = quotes[quoteId];
output({cell: quoteInfo})
}
}
/* Dummy Data */
function getData() {
return '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
}
/* Really simple output for demo purpose */
function output(data, options={}){
if ('row' in data){
let $col = $('<td></td>', options).html(data.row)
let $row = $('<tr></tr>').append($col);
$('tbody').append( $row )
}
else if ('cell' in data){
let $row = $('<tr></tr>')
for( let key in data.cell ){
let $col = $('<td></td>', options).html(data.cell[key])
$row.append($col)
}
$('tbody').append( $row )
}
}
.capitalize {
text-transform: uppercase;
}
td {
min-width: 5rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<thead></thead>
<tbody></tbody>
</table>
Your objects can have any amount of properties and you can choose to sort by whatever object property you want, number or string, if you put the objects in an array.
var item = JSON.parse(json).shipping_method.ups.quote;
Use Object.values() to get array of values of the JSON object and then use slice() method to copy the array of JSON objects and not just make a reference.
var byCost = Object.values(item).slice(0);
Finally you can use sort function for that array of objects.
byCost.sort(function(a,b) {return a.cost - b.cost});
var json = '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
var item = JSON.parse(json).shipping_method.ups.quote;
var byCost = Object.values(item).slice(0);
byCost.sort(function(a,b) {return a.cost - b.cost});
console.log(byCost)
It doesn't seem like you are accessing the right path here... Looking at the JSON you posted you should be attempting to sort shipping_method.ups.quote its also worth noting that shipping_method.ups.quote is an object and must be converted to an Array to invoke .sort as this method lives on the Array prototype.
This can be done several ways but Object.values() is one such way.
you may try the following,
json = JSON.parse(json);
let item = json.shipping_method.ups.quote,
temp = [];
for (let key in item) {
temp.push(item[key]);
}
temp.sort((x, y) => x.cost - y.cost);
json.shipping_method.ups.quote = temp;
converting your object into array and then sort;
As i can see , your problem is to sort the object with cost as their keys should stays same ,
try out this ,
var json = '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
var json = JSON.parse(json);
let data = []
for(var i in json.shipping_method.ups.quote){
data.push(json.shipping_method.ups.quote[i])
data.sort((a,b) => a.cost - b.cost);
}
This create those key agains as they are before
let final = {} ;
data.forEach(el => final[el.code.split('.')[1]] = el);
Finally update the qoute with the latest sorted quotes :
json.shipping_method.ups.quote = final;
At the moment I am stuck with a problem that just seems stupid, but I don't know the answer to it.
I am trying to access this JSON-object:
var custom_fields =
{
"28246": 5123,5124,5125
}
I would like to get each value from that key. I would know how to access it if it was a nested-object, but it isn't sadly (it is coming from an API, which I can't change the JSON-response from sadly)
What I tried already is the following:
for (var key in custom_fields) {
if (custom_fields.hasOwnProperty(key)) {
console.log(key + " -> " + custom_fields[key]);
}
}
The problem here is that the result will be like this:
1 -> 5
2 -> 1
3 -> 2
4 -> 3
5 -> ,
6 -> 5
...etc...
Any suggestions are welcome, I am trying to access it in javascript/Jquery.
Thanks for helping in advance!
I assume that the data is in this format (note the string literals):
var custom_fields = {
"28246": "5123,5124,5125"
}
If that is the case, you can use String.split.
In your case, it would be something like this:
const values = custom_fields['28246'].split(',');
The values of they key 28246 are now stored in the new variable values as an array:
['5123','5124','5125']
If you want to parse all values to integers, I suggest using Array.map:
const valuesAsInt = custom_fields['28246'].split(',').map(value => parseInt(value);
Which will lead to this:
[5123, 5124, 5125]
Disclaimer: When using newer ECMAScript features such as Array.map, be sure to either use a browser which supports this our include a polyfill.
You can access it by using split function which will convert it into an array and then get the values from that array as below code.
var data = {
"28246": '5123,5124,5125'
}
var arr = data['28246'].split(',');
$.each(arr, function( index, value ) {
console.log(value);
});
You can split by ',' and transform each element to integer by using array.map and '+' operator:
var custom_fields =
{
"28246": "5123,5124,5125"
}
custom_fields["28246"] = custom_fields["28246"].split(',').map(el => +el);
console.log(custom_fields);
console.log(custom_fields["28246"][0], custom_fields["28246"][1], custom_fields["28246"][2]);
Hi Everyone,
I have this object:
{"2017-07-09 00:00:00":4,"2017-07-09 09:00:00":1,"2017-07-09 10:00:00":4,"2017-07-09 11:00:00":3,"2017-07-09 12:00:00":16,"2017-07-09 13:00:00":4,"2017-07-09 14:00:00":6,"2017-07-09 15:00:00":5,"2017-07-09 16:00:00":7,"2017-07-09 17:00:00":21,"2017-07-09 18:00:00":25,"2017-07-09 19:00:00":1,"2017-07-10 09:00:00":11,"2017-07-10 10:00:00":4,"2017-07-10 11:00:00":21,"2017-07-10 12:00:00":22,"2017-07-10 13:00:00":23,"2017-07-10 14:00:00":42,"2017-07-10 15:00:00":14,"2017-07-10 16:00:00":36,"2017-07-10 17:00:00":21,"2017-07-10 18:00:00":5,"2017-07-11 09:00:00":16,"2017-07-11 10:00:00":7,"2017-07-11 11:00:00":26,"2017-07-11 12:00:00":34,"2017-07-11 13:00:00":39,"2017-07-11 14:00:00":39,"2017-07-11 15:00:00":30,"2017-07-11 16:00:00":33,"2017-07-11 17:00:00":22,"2017-07-11 18:00:00":1}
I'm trying to divide it per day and get something like this:
First create an array for the day which is 24 hours:
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]
And than calculate how many day is in the object above and get a value for each hours and return something like below. In the object I have 3 days, so I need to return 3 arrays for each days:
[4,0,0,0,0,0,0,0,0,1,10,3,16,...],
[0,0,0,0,0,0,0,0,0,11,4,21,22,23,42,...]
[0,0,0,0,0,0,0,0,0,16,7,26,34,39,39,30,..]
For each hours which is not in the object data return 0 and for each hours that exist return the specified value on the object.
for example on the object the time starts from "2017-07-09 00:00:00":4 and it has the value of 4 and for each hours between that and "2017-07-09 09:00:00":1
return 0.
Any help appreciated. Thanks a lot for your time
You have first to loop into each keys of your object.
After that many solutions, one is to convert your keys into Date object and compare the hour of your object in a for loop.
And retrieve the right data by reconverting your Date obj into your obj property.
Edit
Access your property value without function by using Object.keys and findIndex
I've maybe misunderstand your requirement, but you've a good example
of how to do ;-)
Example of solution
var data ={"2017-07-09 00:00:00":4,"2017-07-09 09:00:00":1,"2017-07-09 10:00:00":4,"2017-07-09 11:00:00":3,"2017-07-09 12:00:00":16,"2017-07-09 13:00:00":4,"2017-07-09 14:00:00":6,"2017-07-09 15:00:00":5,"2017-07-09 16:00:00":7,"2017-07-09 17:00:00":21,"2017-07-09 18:00:00":25,"2017-07-09 19:00:00":1,"2017-07-10 09:00:00":11,"2017-07-10 10:00:00":4,"2017-07-10 11:00:00":21,"2017-07-10 12:00:00":22,"2017-07-10 13:00:00":23,"2017-07-10 14:00:00":42,"2017-07-10 15:00:00":14,"2017-07-10 16:00:00":36,"2017-07-10 17:00:00":21,"2017-07-10 18:00:00":5,"2017-07-11 09:00:00":16,"2017-07-11 10:00:00":7,"2017-07-11 11:00:00":26,"2017-07-11 12:00:00":34,"2017-07-11 13:00:00":39,"2017-07-11 14:00:00":39,"2017-07-11 15:00:00":30,"2017-07-11 16:00:00":33,"2017-07-11 17:00:00":22,"2017-07-11 18:00:00":1}
var dataKeys = Object.keys(data);
var dataKeysParsed = dataKeys.map(function(d){
return new Date(d);
});
var res =[];
for (var i=0;i<=23;i++){
var id = dataKeysParsed.findIndex(function(k){
return k.getHours() == i
});
res.push(id > -1 ? data[dataKeys[id]] : 0);
}
console.log(res);
Hi please see my plunkr below
https://plnkr.co/edit/8cJZsb?p=preview
I have $scope.data which looks like this
$scope.data = [
{
"projectedStart":"2017-01-20T00:00:00"
},
{
"projectedStart":"2017-02-09T00:00:00"
}
];
and $scope.possibleDates that look like this
$scope.possibleDates = [{
"projectedStartDate":"2017-01-25T00:00:00",
"dateName":"January - Week 4 (20/10)"
},
{
"projectedStartDate":"2017-02-01T00:00:00",
"dateName":"February (6/10)"
},
{
"projectedStartDate":"2017-03-01T00:00:00",
"dateName":"March (0/2)"
},
{
"projectedStartDate":"2017-04-05T00:00:00",
"dateName":"April (2/5)"
}]
On the front end dropdown list, I want to be able to display the possibleDates that match closest to the 'projectedStart' date in $scope.data.
I am thinking of doing an angular foreach and looping through each projectedStart date in $scope.data and somehow compare it with each of the dates in $scope.possibleDates and updating $scope.Data's projectedStart with the closest match? Failing miserably so far.
Would greatly appreciate it if someone could point me in the right direction
Look's like you need to look into moment.js. It's a spectacular library for date parsing, formatting, and comparison.
You could put a watcher on possibleDates, and when they change you compute the list that you are after.
The list can be easily written with tools like moment and underscore.
const projectedDate = moment($scope.data[0].projectedStartDate);
const sortedPossibleDates = _.chain($scope.possibleDates)
.each((possibleDate) => {
possibleDate.diff = projectedDate.difference('seconds');
});
.sortBy('diff')
.value()
And voila, the sortedPossibleDates[0] is your best answer
A basic sort function should be able to order the possible dates by how close they are to the chosen start date. Just use new Date(ISOString) to get the numerical timestamps.
From: https://stackoverflow.com/a/11796365/6452040
If you put a function in script.js like this, which finds the closest date (before or after):
$scope.closestStartDate = function(startDate) {
var smallestDifferenceInDates = 1000000000000;//impossibly large value
var closestDateName = 'tmp';
var date = new Date(startDate);
for (var i = 0; i < Object.keys($scope.possibleDates).length; i++) {
var projectedDate = new Date($scope.possibleDates[i].projectedStartDate);
if (Math.abs(date.getTime() - projectedDate.getTime()) < smallestDifferenceInDates) {
smallestDifferenceInDates = Math.abs(date.getTime() - projectedDate.getTime());
closestDateName = $scope.possibleDates[i].dateName;
}
}
return closestDateName;
}
Then change your template code to this:
<tr ng-repeat="d in data">
<td>
{{ closestStartDate(d.projectedStart) }}
</td>
</tr>
You'll get the closest date from $scope.possibleDates (Math.abs() gets the distance between the two, if you want dates after you can leave that off).
I have a situation here. I am having a object like this.
var x ={
"startTime":"10:05Am",
"endTime":"12:05Pm"
}
So my requirement is i want a function which will return a variable with respective time
function getTime(x){
//do something
return timewitHrs;
}
timewitHrs should can be something like this
[{"10am-11pm":55,"11pm-12pm":60,"12pm-1pm":5}]
Is there any way to sort this out
Thanks.
You may use following code
var x ={
"startTime":"10:05am",
"endTime":"11:05am"
}
var start=moment(x.startTime,"hh:mma");
var end=moment(x.endTime,"hh:mma");
var output={};
output.duration=end.diff(start, 'm');//diference in minutes
output.range=start.startOf('h').format("hha")+"-"+end.endOf('h').add(1,'s').format("hha");
output:{ duration: 60, range: '10am-12pm' }
Here I am calculating range based on start time & end time.
If you want something different let me know.