get string of values of certain property from JSON - javascript

I'm trying to get a string of ISBNs from a Google Books bookshelf via their API. Here's my attempt that isn't working. (I'm trying to use this snippet.)
$.getJSON("https://www.googleapis.com/books/v1/users/115939388709512616120/bookshelves/1004/volumes?key=MYAPIKEY", function (data) {
console.log(data);
var allIsbns = [];
for (i = 0; i < data.items.volumeInfo.industryIdentifiers[0].identifier.length; i++) {
allIsbns.push(data.items.volumeInfo.industryIdentifiers[0].identifier[i]);
}
alert(allIsbns);
});
fiddle

Looking at the object logged, data.items is an array (of length data.totalItems it seems). Furthermore, industryIdentifiers[0].identifier seems to be a string, and not an array. Therefore I think you wanted to loop through data.items instead.
Also it may be worth noting you probably should not be going by explicit index on industryIdentifiers unless the the spec calls out a predefined order. I would recommend finding the identifier with type === "ISBN_10":
for (var i = 0; i < data.items.length; i++) {
for (var j = 0; j < data.items[i].volumeInfo.industryIdentifiers.length; j++) {
if (data.items[i].volumeInfo.industryIdentifiers[j].type === "ISBN_10")
allIsbns.push(data.items[i].volumeInfo.industryIdentifiers[j].identifier);
}
}

Related

For-in loops with two variable javascript

Is this possible?
Two variable in for-in loops simulatenous?
for (var i in shear_x && var j in moment_x) {
var overturning_moment = (shear_x[i].results + moment_x[j].results)*moment_arm;
}
Your code implies, at least to me, that you really want a single loop counter applied over both objects, at the same time. I would suggest using a single for loop over the common length of the two objects:
var length = // length of shear_x
for (var i=0; i < length; ++i) {
var overturning_moment = (shear_x[i].results + moment_x[i].results) * moment_arm;
// rest of your loop code
}
If I interpreted your requirement incorrectly, then the only option which might come to mind is two nested loops, something like this:
for (var i in shear_x) {
for (var j in moment_x) {
// your code
}
}

Using .push stops for loop from executing

I have a for loop that suddenly stops working when I try to push to an array. The best way to describe what's going on is just to show my code and try an explain what's going on.
for (var i = 0; i < childs.length; i++) {
if (childs[i].length > 0) {
for (var j = 0; j < amountsValue[i].options.custValues.length; j++) {
var label = amountsValue[i].options.custValues[j].label;
var value = amountsValue[i].options.custValues[j].value;
for (var k = childs[i].length - 1; k >= 0; k--) {
if (childs[i][k].attributes[label] != value) {
childBackup.push(childs[i][k]);
childs[i].splice(k, 1);
}
}
}
amountsValue[i].id = childs[i][0].attributes.internalid;
childs.push(childBackup);
}
}
What's happening is I am looping through an array of items which may or may not have custom options available such as different sizes or colours. The loop will check to see if there are any then get the value and label from the array.
After this, we then loop again to try and match up the values with option values stored within a separate model. The plan is to check if the value is the same as the one stored and if not then splice it from the array. The process of elimination should eventually leave only one option left and that will be used to get the internalid.
During this a back up of the spliced objects is kept so that they can be appended to the array again so that the user can change the option they want. The problem is using childs.push(childBackup) stops the browser form reading the options on amountsValue. This works if the code is removed or it is pushed into another index so I'm really not sure why it isn't working.
Does anyone have any suggestions on how to get this working? I'm sorry if this doesn't make much sense, I've tried to explain it as best I can but let me know if anything needs to be cleared up.
EDIT: I have fixed the issue. Thank you to everyone who suggested ways to solve the problem. As others said, I was trying to manipulate the array I was looping through and changing the length on it. So that part of the code was taken outside the loop and after the initial loop another loop was set up which contained the following code:
for (var i = 0; i < childBackup.length; i++) {
childs[0].push(childBackup[i]);
}
It now works as intended. Thank you.
You are manipulating the array you are looping through.
var count = childs.length;
for (var i = 0; i < count; i++) {
if (childs[i].length > 0) {
for (var j = 0; j < amountsValue[i].options.custValues.length; j++) {
var label = amountsValue[i].options.custValues[j].label;
var value = amountsValue[i].options.custValues[j].value;
for (var k = childs[i].length - 1; k >= 0; k--) {
if (childs[i][k].attributes[label] != value) {
childBackup.push(childs[i][k]);
childs[i].splice(k, 1);
}
}
}
amountsValue[i].id = childs[i][0].attributes.internalid;
childs.push(childBackup);
}
}

for loop to print out multiple arrays with similar names

I've got multiple arrays, like so:
bugNames0 = ["wasp", "roach", "stinkbug", "mantis"];
bugNames1 = ["hornet", "beetle", "ant", "termite"];
bugNames2 = ["gnat", "fly", "grub", "chigger"];
bugNames3 = ["flea", "bed-bug","maggots", "cricket"];
Next up I have this for loop:
function bugLoop() {
for (var i=0; i < 4 ; i++){
console.log(bugNames0[i]);
}
}
That will successfully print the first array to console, or each individually if I manually update the number in the array's name.
But is there a way to do something more like this? This following code bit doesn't work, but I hope it explains what I am trying to do:
for (var i=0, j=0; i < 4; i++) {
console.log(bugNames(i)[j]);
}
}
Here i represents the bugName#, which I would like to get to update through 0 - 3 as the loop runs, printing out only the first option of each array represented by j.
Goal outcome printed to console would be:
"wasp", "hornet", "gnat", "flea"
Or something like that.
If possible I would like solutions only using vanilla JS as I'm working on a project (self assigned exercise) where I'm trying to complete it using vanilla. Kind of a force myself to get the know the language better exercise.
(Also, I've only been coding for 4 months, so sorry if this is a noob question. I couldn't find the answer online anywhere, just lots of loops on printing out arrays normally.)
If you can store your arrays within an array, that would be a better option.
For instance:
bugNames[0] = ["wasp", "roach", "stinkbug", "mantis"];
bugNames[1] = ["hornet", "beetle", "ant", "termite"];
bugNames[2] = ["gnat", "fly", "grub", "chigger"];
bugNames[3] = ["flea", "bed-bug","maggots", "cricket"];
Then you can loop through the bugNames array normally.
You could store all four arrays into one larger array (each bugNames array would simply be an element within this larger array). Let's call it bugCollection:
bugCollection = [["wasp", "roach", "stinkbug", "mantis"], ["hornet", "beetle", "ant", "termite"], ["gnat", "fly", "grub", "chigger"], ["flea", "bed-bug","maggots", "cricket"]]
Alternately, you could keep your variable storage of these arrays and say:
bugCollection = [bugNames0, bugNames1, bugNames2, bugNames3]
Then you could iterate through the larger array, logging out the index at each.
var oneFromEachArray = function(index) {
for (var i = 0; i < bugCollection.length; i++) {
console.log(bugCollection[i][index]);
}
}
oneFromEachArray(0) // Console logs 'wasp', 'hornet', 'gnat', 'flea'
You could try eval
for (var j=0; j < 4 ; j++){
for (var i=0; i < 4 ; i++){
eval("console.log(bugNames" + j + "[i]);");
}
}
You could use the function eval() like this:
for (var i=0, j=0; i < 4; i++) {
console.log(eval('bugNames' + i)[j]);
}
But did you already consider utilizing an array of arrays? Maybe that would be a cleaner way to achieve the same thing.
You can always access your variables using window object. Please use following code to access your variable dynamically.
for (var i=0, j=0; i < 4; i++) {
console.log(window["bugNames"+i][j]);
}

Element sort routine works in Firefox, but crashes in Chrome

I've written the following routine to sort the option elements within a select:
function SortSelect(select)
{
var tmpAry = new Array();
for (var i in select.options)
tmpAry[i] = select.options[i];
tmpAry.sort(function(opta, optb)
{
if (opta.id > optb.id) return 1;
if (opta.id < optb.id) return -1;
return 0;
});
while (select.options.length > 0)
select.options[0] = null;
for (var i in tmpAry)
select.appendChild(tmpAry[i]);
}
It works just fine with Firefox as part of a Greasemonkey script. However, in Chrome, both with and without TamperMonkey, I get this:
Uncaught Error: NOT_FOUND_ERR: DOM Exception 8
SortSelect:125
As is typical for Javascript debuggers, the error line number is totally wrong, so it's difficult to pin down exactly why this is breaking and where. I'm open to suggestions as to why the code is bugging out or ways to effectively debug it (I'm new to Chrome). Thanks.
You should iterate over the options collection using an index, not a for..in loop. The following:
for (var i in select.options) {
tmpAry[i] = select.options[i];
should be:
var options = select.options;
for (var i=0, iLen=options.length; i<iLen; i++) {
tmpAry[i] = options[i];
}
You are likely getting properties from the options collection that aren't option elements, such as length.
You also should not assign "null" to an option. If you want to remove all the options, just set the length of options to zero:
var options.length = 0;
Finally, you should iterate over tmpAray using an index since for..in will not return the options in the same order in every browser and may return non-numeric enumerable properties if there are any, use an index. Also, you can just assign the option back to the select's options collection, there is no need for appendChild:
select.options.length = 0;
for (var i=0, iLen=tmpAry.length; i<iLen; i++) {
select.options[i] = tmpAry[i];
}
If you are not removing any options, you should be able to just assign them in the new order, but some browsers can't handle that so removing them first is best.
Edit
Note that while the options property of a select element is readonly, the properties of an options collection are not. You can assign values (which should be references to option elements) directly to them.
What are you trying to do with this piece of code?
while (select.options.length > 0)
select.options[0] = null;
If the answer is you're trying to clear all the select options, that seems dangerous. I could see how this could easily be an infinite loop.
It looks to me like this would be a lot safer:
for (var i = select.options.length - 1; i > 0; i--) {
select.remove(i);
}
Then, there's an select.options.add() method for adding them back.
FYI, it is also considered risky practice to use this construct on arrays or pseudo arrays:
for (var i in select.options)
for (var i in tmpAry)
as that can pick up properties that have been added to the object in addition to just array elements.
More typing, but safer to use:
for (var i = 0, len = tmpAry.length; i < len; i++) {
// code here
}
These lines can cause an infinite loop or an access violation:
while (select.options.length > 0)
select.options[0] = null;
Also, you do not need to delete the nodes and reinsert them; appendChild() works fine in all browsers to move nodes around.
So, this code will work and should be more efficient than removing and recreating nodes (which can also trash any event listeners). :
See it in action at jsFiddle.
function SortSelect (select)
{
var tmpAry = [];
for (var J = select.options.length - 1; J >= 0; --J)
tmpAry.push (select.options[J] );
tmpAry.sort ( function (opta, optb) {
if (opta.id > optb.id) return 1;
if (opta.id < optb.id) return -1;
return 0;
} );
while (tmpAry.length) {
select.appendChild ( document.getElementById (tmpAry[0].id) );
tmpAry.shift ();
}
}

Why is my nested for loop not working as I expected?

I have trouble dealing with my for loops now, I'm trying to compare two datum, basically it will compare 2 items, then it will write the matches and the mismatches on the webpage.
I managed to write the matches on the webpage, it was working good. But there's a bug in my mismatch compare.
It wrote all the data on the webpage X times, here's my JS code:
function testItems(i1, i2) {
var newArray = [];
var newArray2 = [];
var count = 0;
var count2 = 0;
for(var i = 0; i < i1.length; i++) {
for(var j = 0; j < i2.length; j++) {
if(i1[i] == i2[j]) {
newArray.push(i1[i]);
count++;
} if (i1[i] !== i2[j]) {
newArray2.push(i1[i]);
count2++;
}
}
}
count-=2;
count2-=2
writeHTML(count,count2, newArray, newArray2);
}
The result was horrible for the mismatches:
alt text http://www.picamatic.com/show/2009/03/01/07/44/2523028_672x48.jpg
I was expecting it to show the mistakes, not all the strings.
The issue you're seeing is because of the nested for loop. You are essentially doing a cross-compare: for every item in i1, you are comparing it to every item in i2 (remember that j starts again at 0 every time i advances... the two loops don't run in parallel).
Since I understand from the comments below that you want to be able to compare one array to the other, even if the items in each are in a different order, I've edited my original suggestion. Note that the snippet below does not normalize differences in case between the two arrays... don't know if that's a concern. Also note that it only compares i1 against i2... not both i1 to i2 and i2 to i1, which would make the task a little more challenging.
function testItems(i1, i2) {
var newArray = [];
var newArray2 = [];
for (var i = 0; i < i1.length; i++) {
var found = false;
for (var j = 0; j < i2.length; j++) {
if (i1[i] == i2[j]) found = true;
}
if (found) {
newArray.push(i1[i])
} else {
newArray2.push(i1[i])
}
}
}
As an alternative, you could consider using a hash table to index i1/i2, but since the example of strings in your comment include spaces and I don't know if you're using any javascript helper libraries, it's probably best to stick with the nested for loops. The snippet also makes no attempt to weed out duplicates.
Another optimization you might consider is that your newArray and newArray2 arrays contain their own length property, so you don't need to pass the count to your HTML writer. When the writer receives the arrays, it can ask each one for the .length property to know how large each one is.
Not directly related to the question but you should see this:
Google techtalks about javascript
Maybe it will enlighten you :)
Couple of things about your question. First you should use '!=' instead of '!==' to check inequality. Second I am not sure why you are doing decreasing counts by 2, suggests to me that there may be duplicates in the array?! In any case your logic was wrong which was corrected by Jarrett later, but that was not a totally correct/complete answer either. Read ahead.
Your task sounds like "Given two set of arrays i1 & i2 to find i1 {intersection} i2 and i1{dash} {UNION} i2{dash}) (Group theory notation). i.e. You want to list common elements in newArray and uncommon elements in newArray2.
You need to do this.
1) Remove duplicates in both the arrays. (For improving the program efficiency later on) (This is not a MUST to get the desired result - you can skip it)
i1 = removeDuplicate(i1);
i2 = removeDuplicate(i2);
(Implementation for removeDuplicate not given).
2) Pass through i1 and find i1{dash} and i1 {intersection} i2.
var newArray = [];
var newArray2 = [];
for (var i = 0; i < i1.length; i++)
{
var found = false;
for (var j = 0; j < i2.length; j++)
{
if (i1[i] == i2[j])
{
found = true;
newArray.push(i1[i]); //add to i1 {intersection} i2.
count++;
break; //once found don't check the remaining items
}
}
if (!found)
{
newArray2.push(i1[i]); //add i1{dash} to i1{dash} {UNION} i2{dash}
count2++;[
}
}
3) Pass through i2 and append i2{dash} to i1{dash}
for(var x=0; x<i2.length; x++)
{
var found = false;
//check in intersection array as it'd be faster than checking through i1
for(var y=0; y<newArray.length; y++) {
if( i2[x] == newArray[y])
{
found = true;
break;
}
}
if(!found)
{
newArray2.push(i2[x]); //append(Union) a2{dash} to a1{dash}
count2++;
}
}
writeHTML(count,count2, newArray, newArray2);
I have a feeling that this has to do with your second comparison using "!==" instead of "!="
"!==" is the inverse of "===", not "==". !== is a more strict comparison which does not do any type casting.
For instance (5 != '5') is false, where as (5 !== '5') is true. This means it's possible that you could be pushing to both arrays in the nested loop, since if(i1[i] == i2[j]) and if(i1[i] !== i2[j]) could both be true at the same time.
The fundamental problem here is that a pair of nested loops is NOT the right approach.
You need to walk a pointer through each dataset. ONE loop that advances both as needed.
Note that figuring out which to advance in case of a mismatch is a much bigger problem than simply walking them through. Finding the first mismatch isn't a problem, getting back on track after finding it is quite difficult.

Categories

Resources