Two javascript arrays, using a key to look up - javascript

I have two data structures (they are much longer, these are just excerpts)
var data = [
{count: 6, zip: "78705"},
{count: 4, zip: "78754"},
{count: 33, zip: "78757"}
]
var txcodes = [
{county: "SWISHER", code: "437"},
{county: "TARRANT", code: "439"},
{county: "TAYLOR", code: "441"},
{county: "TRAVIS", code: "453"}
]
I have written code that successfully goes through “data” and takes the zipcode and retrieves the corresponding county (from an external website via HTTP request). It returns a structure that looks like
results = {
TRAVIS: 8,
TAYLOR: 1
}
(8 and 1 are examples of counters for how many times a zipcode from data occurs…basically a running count).
What I need to do next is use the keys from results to look up what the corresponding code in txcodes is. How do I do this?
var currentCounty = str.result[0].County
returns the county from results.
console.log(txcodes[i].county + " " + txcodes[i].code)
prints the county & code from txcodes.
I’m a little confused on how to do this. It seems like a relatively simple concept but I can’t seem to get the desired result. Can someone please point me in the right direction?

If county names are unique and if you are going to be making repeated lookups, you should build a "map" of the codes out of the array:
var txcodesByCounty = txcodes.reduce(function(p, c) {
p[c.county] = c.code;
return p;
}, {});
You can then look up codes directly from this map.

Build a lookup map like this :
var lookupMap = {};
for (var i = 0; i < txcodes.length; i++) {
var element = txcodes[i];
lookupMap[element.county] = element;
}
Then you can simply do this to print the desired output :
console.log(lookupMap[currentCounty].county + " " + lookupMap[currentCounty].code);

If the county in your result is only available as a key, you'll need to for..in, Object.keys or Object.getOwnPropertyNames to access them.
After, access the details via a map as others have suggested
var county, found = [];
for (county in results)
found.push(map[county]);

So what you get back from your HTTP request is a simple object, and you need to access its property names. You can do that easily with Object.keys:
resultKeys = Object.keys(result);
This will give you an array of the object properties:
[ "TRAVIS", "TAYLOR" ]
You can easily iterate over this array now, and inside you ask your result object for its value:
for (var i = 0; i < resultKeys.length; i++) {
console.log(resultkeys[i] + ": " + result[resultkeys[i]]);
}
Using this technique, you can use for example underscore.js libary to easily filter for your desired data:
for (var i = 0; i < resultKeys.length; i++) {
console.log(_.filter(txcodes , function(key){ return txcodes.county== resultkeys[i]; }));
}

Related

Javascript Array of Objects and Unique Values

I have an array of objects that looks like this:
[
{"name":"Andrea","from":"USA","Food":"Candy"},
{"name":"Matt","from":"Taiwan","Food":"Chicken"},
{"name":"Roddy","from":"USA","Food":"Rice"},
{"name":"Andy","from":"Great Britain","Food":"Steak"},
];
Is there a way to get the list of all countries from the array above, and get rid of the repeated ones?
So from the list above, the list I am to obtain is:
["USA", "Taiwan", "Great Britain"]
Thank you!
Just loop over people and insert unique countries in a new array. Here is an example.
var countries = [];
var people = [
{"name":"Andrea","from":"USA","Food":"Candy"},
{"name":"Matt","from":"Taiwan","Food":"Chicken"},
{"name":"Roddy","from":"USA","Food":"Rice"},
{"name":"Andy","from":"Great Britain","Food":"Steak"},
];
for (var i = 0, l=people.length; i < l; i++) {
if(people[i] && people[i].from) {//ensure country exists
if (countries.indexOf(people[i].from) == -1) {//ensure unique
countries.push(people[i].from);
}
}
}
Yet another variant with reduce
var arr = [
{"name":"Andrea","from":"USA","Food":"Candy"},
{"name":"Matt","from":"Taiwan","Food":"Chicken"},
{"name":"Roddy","from":"USA","Food":"Rice"},
{"name":"Andy","from":"Great Britain","Food":"Steak"},
];
var countries = arr.reduce(function(acc, cur){
if(!acc.map[cur.from]){
acc.map[cur.from]=true;
acc.result.push(cur.from);
}
return acc;
}, {result:[], map:{}}).result;
var arr = [
{"name":"Andrea","from":"USA","Food":"Candy"},
{"name":"Matt","from":"Taiwan","Food":"Chicken"},
{"name":"Roddy","from":"USA","Food":"Rice"},
{"name":"Andy","from":"Great Britain","Food":"Steak"},
];
var countries = arr.reduce(function(acc, cur){
if(!acc.map[cur.from]){
acc.map[cur.from]=true;
acc.result.push(cur.from);
}
return acc;
}, {result:[], map:{}}).result;
document.getElementById('countries').innerHTML = countries.join();
<span id="countries"></span>
If you are already using the excellent Lodash library, the following will do it for you neatly in one line:
var uniqueCountries = _(dataArray).pluck('from').unique().value();
UnderscoreJS has similar functionality using chaining.
For D3.js, the following will do it:
var uniqueCountries = d3.set(dataArray.map(function (x) { return x.from; })).values();
Without doing the unique-ifying on the server and returning that data separately, there is no way to get around looping through all records at least once to do this. For 1000 records or so, though, this will still be very fast.
For plain JS, see other answers.
I'd loop over the Array and put the country into an array if it is not yet inside that array.

Hash Tables in javascript

I am trying to build a data structure.
In my limited knowledge, 'hash table' seems to be the way to go. If you think there is an easier way, please suggest it.
I have two, 1-dimensional arrays:-
A[] - contains names of badges (accomplishment)
B[] - contains respective dates those achievements were accomplished from array A[].
An achievement/accomplishment/badge can be accomplished more than one time.
Therefore a sample of the two arrays:-
A['scholar', 'contributor', 'teacher', 'student', 'tumbleweed', 'scholar'.....,'scholar',......]
B['1/2010', '2/2011', '3/2011', '6/2012', '10/2012', '2/2013',......'3/2013',........]
What I want to achieve with my data structure is:-
A list of unique keys (eq:- 'scholar') and all of its existing values (dates in array B[]).
Therefore my final result should be like:-
({'scholar': '1/2010', '2/2013', '3/2013'}), ({'contributor' : ........})..........
This way I can pick out a unique key and then traverse through all its unique values and then use them to plot on x-y grid. (y axis labels being unique badge names, and x axis being dates, sort of a timeline.)
Can anyone guide me how to build such a data structure??
and how do I access the keys from the data structure created.... granted that I don't know how many keys there are and what are their individual values. Assigning of these keys are dynamic, so the number and their names vary.
Your final object structure would look like this:
{
'scholar': [],
'contributor': []
}
To build this, iterate through the names array and build the final result as you go: if the final result contains the key, push the corresponding date on to its value otherwise set a new key to an array containing its corresponding date.
something like:
var resultVal = {};
for(var i = 0; i < names.length; ++i) {
if(resultVal[names[i]]) {
resultVal[names[i]].push(dates[i]);
} else {
resultVal[names[i]] = [dates[i]];
}
}
Accessing the result - iterating through all values:
for(var key in resultVal) {
var dates = resultVal[key];
for(var i = 0; i < dates.length; ++i) {
// you logic here for each date
console.log("resultVal[" + key + "] ==> " + resultVal[key][i]);
}
}
will give results like:
resultVal[scholar] ==> 1/2010
resultVal[scholar] ==> 2/2013
resultVal[scholar] ==> 3/2013
resultVal[contributor] ==> 2/2011
resultVal[teacher] ==> 3/2011
resultVal[student] ==> 6/2012
resultVal[tumbleweed] ==> 10/2012
You can try this...
var A = ['scholar', 'contributor',
'teacher', 'student', 'tumbleweed', 'scholar','scholar'];
var B = ['1/2010', '2/2011',
'3/2011', '6/2012', '10/2012', '2/2013','3/2013'];
var combined = {};
for(var i=0;i<A.length;i++) {
if(combined[A[i]] === undefined) {
combined[A[i]] = [];
}
combined[A[i]].push(B[i]);
}
Then each one of the arrays in combined can be accessed via
combined.scholar[0]
or
combined['scholar'][0]
Note the === when comparing against undefined

Ordered JSONObject

I have a servlet which talks with the database then returns a list of ordered (ORDER BY time) objects. At the servlet part, I have
//access DB, returns a list of User objects, ordered
ArrayList users = MySQLDatabaseManager.selectUsers();
//construct response
JSONObject jsonResponse = new JSONObject();
int key = 0;
for(User user:users){
log("Retrieve User " + user.toString());
JSONObject jsonObj = new JSONObject();
jsonObj.put("name", user.getName());
jsonObj.put("time", user.getTime());
jsonResponse.put(key, jsonObj);
key++;
}
//write out
out.print(jsonResponse);
From the log I can see that the database returns User objects in the correct order.
At the front-end, I have
success: function(jsonObj){
var json = JSON.parse(jsonObj);
var id = 0;
$.each(json,function(i,item) {
var time = item.time;
var name = item.name;
id++;
$("table#usertable tr:last").after('<tr><td>' + id + '</td><td width="20%">' + time +
'</td><td>' + name +
'</td></tr>');
});
},
But the order is changed.
I only noticed this when the returned list has large size (over 130 users).
I have tried to debug using Firebug, the "response tab" in Firebug shows the order of the list is different with the log in the servlet.
Did i do anything wrong?
EDIT: Example
{"0":{"time":"2011-07-18 18:14:28","email":"xxx#gmail.com","origin":"origin-xxx","source":"xxx","target":"xxx","url":"xxx"},
"1":{"time":"2011-07-18 18:29:16","email":"xxx#gmail.com","origin":"xxx","source":"xxx","target":"xxx","url":"xxx"},
"2":
,...,
"143":{"time":"2011-08-09 09:57:27","email":"xxx#gmail.com","origin":"xxx","source":"xxx","target":"xxx","url":"xxx"}
,...,
"134":{"time":"2011-08-05 06:02:57","email":"xxx#gmail.com","origin":"xxx","source":"xxx","target":"xxx","url":"xxx"}}
As JSON objects do not inherently have an order, you should use an array within your JSON object to ensure order. As an example (based on your code):
jsonObj =
{ items:
[ { name: "Stack", time: "..." },
{ name: "Overflow", time: "..." },
{ name: "Rocks", time: "..." },
... ] };
This structure will ensure that your objects are inserted in the proper sequence.
Based on the JSON you have above, you could place the objects into an array and then sort the array.
var myArray = [];
var resultArray;
for (var j in jsonObj) {
myArray.push(j);
}
myArray = $.sort(myArray, function(a, b) { return parseInt(a) > parseInt(b); });
for (var i = 0; i < myArray.length; i++) {
resultArray.push(jsonObj[myArray[i]]);
}
//resultArray is now the elements in your jsonObj, properly sorted;
But maybe that's more complicated than you are looking for..
As mentioned by ghayes , json objects are unordered.
There are multiple solutions to this problem.
You can use array and the sort it to get the ordered list.
You can use gson library to get the desired order of elements.
I would prefer the second option as it is easy to use.
As JSONObject is order less and internally uses Hashmap. One way to use it to download the all classes from org.json and use in your project directly by changing the internal HashMap implementation to LinkedHashMap in JSONObject.java file. below is the sorted json files
https://github.com/abinash1/Sorted-Json-Object

Looping to Parse JSON Data

Description and Goal:
Essentially data is constantly generated every 2 minutes into JSON data. What I need to do is retrieve the information from the supplied JSON data. The data will changed constantly. Once the information is parsed it needs to be captured into variables that can be used in other functions.
What I am stuck in is trying to figure out how to create a function with a loop that reassigns all of the data to stored variables that can later be used in functions.
Example information:
var json = {"data":
{"shop":[
{
"carID":"7",
"Garage":"7",
"Mechanic":"Michael Jamison",
"notificationsType":"repair",
"notificationsDesc":"Blown Head gasket and two rail mounts",
"notificationsDate":07/22/2011,
"notificationsTime":"00:02:18"
},
{
"CarID":"8",
"Garage":"7",
"Mechanic":"Tom Bennett",
"notificationsType":"event",
"notifications":"blown engine, 2 tires, and safety inspection",
"notificationsDate":"16 April 2008",
"notificationsTime":"08:26:24"
}
]
}};
function GetInformationToReassign(){
var i;
for(i=0; i<json.data.shop.length; i++)
{
//Then the data is looped, stored into multi-dimensional arrays that can be indexed.
}
}
So the ending result needs to be like this:
shop[0]={7,7,"Michael Jamison",repair,"Blown Head gasket and two rail mounts", 07/22/2011,00:02:18 }
shop[1]={}
You can loop through your JSON string using the following code,
var JSONstring=[{"key1":"value1","key2":"value2"},{"key3":"value3"}];
for(var i=0;i<JSONstring.length;i++){
var obj = JSONstring[i];
for(var key in obj){
var attrName = key;
var attrValue = obj[key];
//based on the result create as you need
}
}
Hope this helps...
It sounds to me like you want to extract the data in the "shop" property of the JSON object so that you can easily reference all of the shop's items. Here is an example:
var json =
{
"data":
{"shop":
[
{"itemName":"car", "price":30000},
{"itemName":"wheel", "price":500}
]
}
},
inventory = [];
// Map the shop's inventory to our inventory array.
for (var i = 0, j = json.data.shop.length; i < j; i += 1) {
inventory[i] = json.data.shop[i];
}
// Example of using our inventory array
console.log( inventory[0].itemName + " has a price of $" + inventory[0].price);
Well, your output example is not possible. You have what is a list of things, but you're using object syntax.
What would instead make sense if you really want those items in a list format instead of key-value pairs would be this:
shop[0]=[7,7,"Michael Jamison",repair,"Blown Head gasket and two rail mounts", 07/22/2011,00:02:18]
For looping through properties in an object you can use something like this:
var properties = Array();
for (var propertyName in theObject) {
// Check if it’s NOT a function
if (!(theObject[propertyName] instanceof Function)) {
properties.push(propertyName);
}
}
Honestly though, I'm not really sure why you'd want to put it in a different format. The json data already is about as good as it gets, you can do shop[0]["carID"] to get the data in that field.

What's the best way to query an array in javascript to get just the items from it I want?

I have an array like this (with just over 3000 objects instead of the 3 here):
items = [{name:'charlie', age:'16'}, {name:'ben', age:'18'}, {name:'steve', age:'18'}]
What's the best way to return an array with just the objects of people who are 18? So I want:
items = [{name:'ben', age:'18'}, {name:'steve', age:'18'}]
The best I can think of is this (using jQuery):
newArray = []
$.each(items, function(index, item) {
if(item.age=='18') {
newArray.push(item)
}
})
Considering that there's 3000 thousand objects, and also that I'll be doing that comparison up to fifty times in one go, that's a lot of looping. Is there a better way?
You can use pure javascript
var wanted = items.filter( function(item){return (item.age==18);} );
And if your browser does not support the 1.6 version of javascript you can find an implementation of the filter method at https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
Update
Speedwise there is a huge varying (had an error in the test) difference from a normal loop (depending on browser).. Have a look at this little test i made at http://jsperf.com/array-filter-vs-loop/3
Get matched item and items using find() and filter() method
If you want first matched single item, use find() method which returns single object.
If you want all matched , use filter() method which returns array of objects.
let items = [{name:'charlie', age:'16'},
{name:'ben', age:'18'},
{name:'steve', age:'18'}]
let all = items.filter(item=> item.age==='18')
console.log(all);
let single = items.find(item=> item.age==='18')
console.log(single);
If you're going to do the search often it may be best to keep a version of your data in a form that is quick to access.
I've used underscore.js (http://documentcloud.github.com/underscore/) to make it easy for myself, but this code here will create an object that holds your data indexed by the age field.
You end up with something that looks like this:
{
"16": [
{
"name": "charlie",
"age": "16"
}
],
"18": [
{
"name": "ben",
"age": "18"
},
{
"name": "steve",
"age": "18"
}
]
}
The code:
var itemsByAge = _(items).reduce(function(memo, item) {
memo[item.age] = memo[item.age] || [];
memo[item.age].push(item);
return memo;
}, {});
alert(JSON.stringify(itemsByAge["18"]));
No matter which method you choose (items.filter or any "query language" for json), a for loop is inevitable.
If performance is a concern, I would recommend you to use pure javascript instead of libraries like jQuery which will add overheads to the whole processing as is evident here.
Thus, your code would look like:
var newArray = [];
for(var i=0;i<items.length;i++) {
var item = items[i];
if(item.age == '18') {
newArray.push(item);
}
});
making use of javascript magnificent function eval() which evaluates string as code at runtime, we can define a prototype method for Array type
Array.prototype.where = function (query) {
var newArray = [];
for(var i=0; i<this.length; i++) {
var item = this[i];
if(eval( "item" + query )) {
newArray.push(item);
}
}
return newArray;
};
and use it with any array, passing the query as string
var newArray= items.where('.age >= 18');
Use the filter method of the array, it calls the provided callbackfunction once for each element in an array.
array.filter(<callbackfucntion>[, <Object to use>])
once i had such problem and i solved it like this
1- create an array of array
2- each index create an Index record
e.g.
var pAry=[];
var cAry=[{name:'ben', age:'18'}, {name:'steve', age:'18'}]
pAry[17]=cAry;
This way when u require person with age 18, you will get on index 17.

Categories