I have a json object that looks something like:
{
posts: [
{id: 56, title: 'something', date: '10-10-10 00:00:00'},
{id: 57, title: 'Apples', date: '10-10-16 00:00:00'},
]
}
And I am trying to learn how to manipulate data structures in Javascript. I would like to use jquery to reorder these based on the posts attributes, so you might reorder based on date, title or id (default is id).
How ever being a novice, I have no idea where to start I have seen this answer andI dont think its the direction I want to go.
Would the resulting out put be in the same structure? How could I create a collections of models based off this kind of "re-ordering".
The idea is to allow for editing and publishing of one model in a collection, based off the attribute used to re-order or "sort" the collection, thus allowing for faster processing - so I don't always have to pass the whole collection to the server when I really just want to update one model in the collection.
Take a look at the JavaScript array.sort method. It may do what you want.
var posts = [{"id": 57, "title": "something"}, {"id": 56, "title": "something else"}];
posts.sort(function(a, b) { if (a.id < b.id) { return -1; } else { return 1; } });
for (var i=0; i<posts.length-1; i++) {
console.log(posts[i].title);
}
// prints "something else" followed by "something"
The sort method takes a function which is passed two elements, a and b, and you can return -1 if a is less than b, 0 if they are equal, and 1 if a is greater than b.
Note that my posts variable above is just a simplified version of what would be o.posts if your described JSON was stored at o. Also note that sort sorts in place, meaning it will change the array it operates over.
Related
I am using IE 11.
I have an object array that is grouped using the lodash library. I want to be able to query the object and based on certain conditions come up with sums/counts. So for example, I have this object array.
I would like to have the result seen below but in an object like the image above
As you can see, each company in the group should have certain values based on the following criteria
How many times does 'company x' have a Total Count >3?
How many times does 'company x' have expectingFunding eq ‘Yes’>
How many times does 'company x' have fundedOnIKNS eq ‘No’?
I've tried quite a bit in the last couple of days but not success. I first declared 2 arrays so I can capture the unique values of company name and program. I also created an object to update when conditions were met. The only successful thing I was able to get was to keep it in an grouped object. All the values in the new object were wrong.
Here's an excerpt of the code:
const companiesSummary = {};
for (const company of Object.keys(myData)) {
companiesSummary[company] = {
totalCount: 0,
expectedFunding: 0,
IKNSFunding: 0,
};
for (const { TotalCount, expectedFunding, fundedOnIKNS } of myData[company]) {
companiesSummary[company].totalCount += TotalCount;
companiesSummary[company].expectedFunding += expectedFunding === "Yes";
companiesSummary[company].fundedOnIKNS += fundedOnIKNS === "Yes";
}
}
I get the error,
TypeError: myData[company] is not iterable
Here's a link to the pen
I would still like the result to be in an object array, so I can create an html table later. Any help would be much appreciated. Thank you!
Your code isn't working because you're taking myData, an array, accessing myData[company], an object (company is 0, 1, ...), and you can't iterate through an object with for...of. myData is definitely not the same object in your screenshot.
Your code excerpt might work if your myData object were the object in your screenshot.
I have an object ( array of hashes ) and I need to convert it into ordered key value pairs.
This is object:
var places_info = [
{"place_id":180,"name":"Abc","city":"Gotham"},
{"place_id":161,"name":"Def","city":"Sin City"},
{"place_id":178,"name":"Ghi","city":"Timbuktu"},
{"place_id":179,"name":"Jkl","city":"Acapulco"},
{"place_id":174,"name":"Mno","city":"Desire"}
];
And I need function to return key/value (place_id/name) pairs in same (alphabetical by name) order:
{
'180': 'Abc',
'161': 'Def',
'178': 'Ghi',
'179': 'Jkl',
'174': 'Mno'
}
Actual use: I need it as input for Jeditable Select-input (actual example on demo page). Select-type needs for data-property key/value pairs or function which returns them. So far I got select options in random order, but--as you may imagine--I need them ordered by value....
As for Jeditable the data may be just a fake hash (string formed as JSON key/value pairs), my only solution is like this:
var arr = new Array;
for ( i in places_info ) {
arr.push( "'" + places_info[i].place_id + "':'" + places_info[i].name + "'" );
}
var uglyString = '{' + arr.join(',') + '}';
Is there some more elegant and intuitive approach for such goal? I'd like to keep my data in proper data structure. Converting it to flat string seems like hack.
Edit
I must reconsider the problem. I did not test Jeditable with generated string and seems it evals string into hash and then my desired order is gone. So, this problem needs different approach. Maybe I need make my own datatype for Jeditable. But this seems like different question.
Until ES6, there is NO guaranteed order for properties on a Javascript object. They are unordered. If you need order and need to support environments before ES6, then you can't just use properties on an object and get a guaranteed order of those properties.
So your choice is to pick some other data structure that can reliably express order. Collapsing it all down to a string like you've done is one choice, though that means it has to be re-parsed in order to be useful to Javascript. It would be better to keep it in some natively accessible Javascript format. For order, that means using an array.
You can return ordered pairs by returning an array for the ordering and then there are several choices for what to put in the array. Here are several examples of ordered key/value pairs:
// array of objects
var a = [{key: "greeting", value: "hello"}, {key: "salutation", value: "welcome"}];
Since that seems a little verbose to me, I often use a shortcut that just knows that every other element is a key, then value, then key, then value and doesn't have to spell out those property names over and over:
// alternating key/value
var a = ["greeting", "hello", "salutation", "welcome"];
Or, you could put each ordered pair in an array itself so each sub-array is an ordered pair:
// sub-arrays
var a = [["greeting", "hello"], ["salutation", "welcome"]];
The properties order in objects are not guaranted in JavaScript, you need to use an Array.
Take a look at this:
var obj = {
'180': 'Abc',
'161': 'Def',
'178': 'Ghi',
'179': 'Jkl',
'174': 'Mno'
};
for (var i in obj) { console.log(i); };
will give you:
161, 174, 178, 179, 180
Just use JavaScript's native Map data structure. It preserves order. We are now way past 2015 so it should be standard in almost any runtime.
e.g.
const m = new Map([["greeting", "hello"], ["salutation", "welcome"]])
See Also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
I'm looking for a way to take a bunch of JSON objects and store them in a data structure that allows both fast lookup and also fast manipulation which might change the position in the structure for a particular object.
An example object:
{
name: 'Bill',
dob: '2014-05-17T15:31:00Z'
}
Given a sort by name ascending and dob descending, how would you go about storing the objects so that if I have a new object to insert, I know very quickly where in the data structure to place it so that the object's position is sorted against the other objects?
In terms of lookup, I need to be able to say, "Give me the object at index 12" and it pulls it quickly.
I can modify the objects to include data that would be helpful such as storing current index position etc in a property e.g. {_indexData: {someNumber: 23, someNeighbour: Object}} although I would prefer not to.
I have looked at b-trees and think this is likely to be the answer but was unsure how to implement using multiple sort arguments (name: ascending, dob: descending) unless I implemented two trees?
Does anyone have a good way to solve this?
First thing you need to do is store all the objects in an array. That'll be your best bet in terms of lookup considering you want "Give me the object at index 12", you can easily access that object like data[11]
Now coming towards storing and sorting them, consider you have the following array of those objects:
var data = [{
name: 'Bill',
dob: '2014-05-17T15:31:00Z'
},
{
name: 'John',
dob: '2013-06-17T15:31:00Z'
},
{
name: 'Alex',
dob: '2010-06-17T15:31:00Z'
}];
The following simple function (taken from here) will help you in sorting them based on their properties:
function sortResults(prop, asc) {
data = data.sort(function(a, b) {
if (asc) return (a[prop] > b[prop]);
else return (b[prop] > a[prop]);
});
}
First parameter is the property name on which you want to sort e.g. 'name' and second one is a boolean of ascending sort, if false, it will sort descendingly.
Next step, you need to call this function and give the desired values:
sortResults('name', true);
and Wola! Your array is now sorted ascendingly w.r.t names. Now you can access the objects like data[11], just like you wished to access them and they are sorted as well.
You can play around with the example HERE. If i missed anything or couldn't understand your problem properly, feel free to explain and i'll tweak my solution.
EDIT: Going through your question again, i think i missed that dynamically adding objects bit. With my solution, you'll have to call the sortResults function everytime you add an object which might get expensive.
I am working on a Javascript web application (SPA) with RESTful api on the back-end. In my client-side datacontext I want to add objects to my model graph and then send the whole graph to server at once.
Suppose the following example:
I have a Person object in my model which itself has an array of say PhoneNumbers as a property. Now I load a Person from api for edditing and map it to my model. Suppose I want to add some phone number objects to my PhoneNumbers. For this I add each number e.g. {"id": 0, "number": 6536652226} with an id of zero to my client model and send the whole graph to server when user clicks save. In server I add the objects with the id of zero (new objects) to database with auto-incremented ids.
I am doing my project based on a tutorial. They do something like this to add objects to context:
var items = {},
// returns the model item produced by merging json obj into context
mapJsonToContext = function (json) {
var id = mapper.getJsonId(json);
var existingItem = items[id];
items[id] = mapper.fromDto(json, existingItem); //returns the mapped obj
return items[id];
},
add = function (newObj) {
items[newObj.id()] = newObj;
}
The problem is that if I use this method I wouldn't be able to remove by id the newly-added-not-yet-saved items in client-side 'cause all the ids are zero!
Any suggestions to fix this, or do I need a totally different approach?
First of all, two little misconceptions I've spot:
1) Forget about "associative arrays". Numeric arrays are the only kind arrays you have; the other constructs are just "objects" (this is not PHP).
2) If it's JSON it's a string, not an object.
Other than that, you can of course use an arbitrary value to represent "new" (though I'd probably use null rather than 0) as soon as you don't use such value to uniquely identify the yet-to-add item. E.g., this is just fine:
[
{"id": 0, "number": "6536652226"},
{"id": 0, "number": "9876543210"},
{"id": 0, "number": "0123456789"}
]
This is not:
// WRONG!!!!
{
0: "6536652226",
0: "9876543210",
0: "0123456789"
}
}
And of course you cannot find numbers by ID if they still don't have an ID. You need to choose:
Retrieve the generated ID from DB and update your local data
Delete by number
Create a localId property on newly created client-side objects, and use that as your key when reconciling server returned-data. Obviously the server would have to return this localId to you.
I have some trouble figuring out how to sort a BackboneJS collection containing linked items.
Is it at all possible to do efficiently? (I am thinking of making one returning the count of previous elements, but that is really inefficient)
What should the comparator be? - and is a double linked list required?
My items look like
[
{
id: 1,
name: 'name',
previousItem: 2
},
{
id: 2,
name: 'othername',
previousItem: null
}
]
Here is the basic code to build the collection. I'm assuming you are using a Backbone Model here. In the loop, you need to add your models to the front of the collection (unshift) since you only know the previous item.
The key here is knowing what the last item is though. If you don't know it, then this will not work.
model = frontItem;
while (model != null) {
collection.unshift(model);
model = model.attr('previousItem')
}
there is a discussion about this on github, you can also use comparator, if you want to use comparator you need underscore
var PhotoCollection = Backbone.Collection.extend({
model: Photo,
comparator: function(item) {
return item.get('pid');
}
});