Searching an array for values ending in certain characters in JavaScript - javascript

So Im looking for help for writing a simple function in javascript. What I am trying to do is create an array of 6 name and print only those ending in "ie" or "y".
Here is my code - any help is appreciated. It unfortunately never reaches the function :(
//An array of names
var nameList = new Array("Freddie", "Mary", "Thomas", "Suzie", "Terry", "Kevin");
//Prints names before searching
document.write(nameList);
function e_names(nameList) {
for (var index = 0; index < arrayList.length; index++) {
var name = arrayList[index];
if (name == /\bie\b/ || name == /\by\b/)
document.write("",name, " </ br>");
index++;
} //End of for loop
} //End if method

Use /(ie|y)$/ ($ is used to match the end) to test it:
if (/(ie|y)$/.test(name))

It unfortunately never reaches the function :(
In your code, you are defining a function but then never executing it. Execute it like so:
e_names(namesList);
The loop has a bug:
for (var index = 0; index < arrayList.length; index++) {
arrayList is not defined, at least not in this code. It could be a previously defined or global variable, but then why does the function take a parameter called nameList? I think this is a simple typo.
if (name == /\bie\b/ || name == /\by\b/)
I am not sure what it means to equal a regular expression, but I would hazard a guess it won't do what you want. I think you want the .test function such as:
if (/\bie\b/.test(name) || /\by\b/.test(name))
Your pattern includes \b, the word boundary both before and after the y or ie. Therefore, it will only match strings that have i or ie as exact strings or with spaces around them. They won't match array or key or cookie. I think you meant to anchor them to end of string as suggested by #xdazz's answer. He even OR'ed the two expressions together for you:
if (/(ie|y)$/.test(name))
Finally, you double-increment index:
index++;
This will only iterate over "Freddie", "Thomas", and "Terry" because you increment twice. The index++ at the end of the loop construct is sufficient. Take this line out.
Altogether now:
//An array of names
var nameList = [ "Freddie", "Mary", "Thomas", "Suzie", "Terry", "Kevin" ];
//Prints names before searching
document.write(nameList);
function e_names(names) {
for (var index = 0; index < names.length; index++) {
var name = arrayList[index];
if (/(ie|y)$/.test(name)) {
document.write("",name, " </ br>");
}
} //End of for loop
} //End if method
e_names(nameList);
Note that I renamed the parameter so that it doesn't cause confusion with scoping and I also put curly braces around your if block. I usually don't change other people's code style, but I felt it was needed in this case to make it clearer.
I also changed the array construction to use the literal notation. Much debate has been had around the new Array constructor. It's probably safe for this example, but if there is a single element or the array contents are dynamic, it gets confusing. For example, what does new Array(17) mean? It means create an array with 17 null references in it. It does not create an array with the number 17 in it. For that reason, my advice is to use the [ ] syntax. For details, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

Related

Delete two redundant symbols from each element of a string array

I think this question should be an easy one. I use a regex expression which, actually is:
str_pow = str_input.match(/(?:x)[^][+-]?\d{1,4}\s/g);
The problem lays in that I need only numbers, though they're still of string type(don't think about this), but not this part x^. Currently the how str_pow looks like is this
This means two things: I've to either edit my regex mask, or to find a way to cut the first two "x^" characters of for each element i of the array. Can you help me to do this, because I tried to slice but it was an unsuccessful experiment.
You can loop the array:
var a = ["x^5 ", "x^4 ", "x^2 ", "x^1 "];
for(var i = 0; i< a.length; i++) {
a[i] = parseInt(a[i].substring(2, a[i].length).trim(), 10);
}
console.log(a);

Why Runtime error if input array element are parsed to integer altogether in javascript?

I was working on counting sort1 problem on hackerrank. I am using JavaScript to solve the problem.
Standard input is providing a number and an array which I was reading like this
var inp = input.split('\n')
var n = parseInt(inp[0]); //Number of elements
var ar = inp[1].split(' ').map(function(item){
return parseInt(item);
}); //Array of numbers.
I was using above code in almost all of my solutions, it always worked.
Then I process the above array ar in for loop which is giving runtime error in one of the test cases(last testcase).
for(var i = 0; i < n; i++) {
var number = ar[i];
//more code
}
But if I don't parse elements of the array using map function but parse them later in for loop, one by one, I don't get any error.
var ar = in[1].split(' '); //Array of numbers in string format
for(var i = 0; i < n; i++) {
var number = parseInt(ar[i]);
//more code
}
Can Anyone explain Why?
in is a keyword, and you are trying to use it as a variable. I'm not sure why it says "Runtime Error", since this is actually a parsing error. Once renamed to something else, I could run the first two paragraphs error-free.
The only problem I remember having on Hackerrank that the .split() method often gave an empty string ("") as the last element of the array. Probably that's why you failed on the last test case.
Make your logic like:
if(arr[i] !== "")
// perform operations
else
break;
Also, you can't use in as a identifier because it is a reserved keyword.

Custom function for Google Spreadsheet - handling the array passed from the spreadsheet

I am trying to build a simple script to work with a Google Spreadsheet. The spreadsheet takes input from a Google Form, so there is a series of values in the spreadsheet like this:
My goal is to write a script that would strip the number from each form input in a user-specified range, then add all the numbers to provide a single score. So, for example, the user could type =sumColumns(H2:K2) in a cell, and it would return the sum of the scores (for the sample screenshot I posted, it would return the result of 3+3+0+3, 9).
Here is the code that I wrote to do this:
function sumColumns(values) {
var sum = 0;
for(var i = 0; i <= values.length; i++){
var input = values[0][i];
var x = input.toString();
var y = x.charAt(0);
var num = parseInt(y);
sum += num;
}
return sum;
}
The problem is that it only ever seems to add two values together. So, when I put =sumColumns(H2:K2) in a cell in the spreadsheet, it only returns 6. Also, on line 3, if I change it from i <= values.length to i < values.length it only adds one number, so that I get 3 as a result. My guess is that I am misunderstanding the way that the Google Spreadsheet values are passed to the function, but I have been completely unable to make it work. I'd really appreciate any help!
Oops - edited & saved the question, wrote an answer - and forgot to save it. I let Serge beat me to it! And, as usual, Serge's answer works well (with integer values). But you did ask about how things worked, so here you go.
When you give a Custom Function a range as a parameter, H2:K2 in this case, the function receives a two-dimensional array, equivalent to the return value of Range.getValues(). You can test this easily, by (temporarily) changing your function to return a JSON representation of the parameter:
function sumColumns(values) {
return JSON.stringify(values); // For debugging, just return string showing values
...
Here's what you'll see in the cell that contains =sumColumns(H2:K2):
[["3 (Rarely)","3 (Frequently)","0 (Never)","3 (Frequently)"]]
That's showing an Array enclosed by [ .. ], with another Array inside, also enclosed by square brackets, and that array has four elements. If we change the range to be H2:K3 instead, we get this (with whitespace added for clarity):
[
["3 (Rarely)","3 (Frequently)","0 (Never)","3 (Frequently)"],
["","","",""]
]
Now that you know that, it's easy to see why your function was giving the results it did.
First, for(var i = 0; i <= values.length; i++) is using the wrong array bounds to loop over, since values.length will tell us how many rows are in values. In H2:K2, that length is 1. Instead, we need to be looping over the columns in the first row (values[0]), with its 4 cells.
You were wondering about < vs <= for this loop - we do need to use < since it's a 0-based index, and .length returns a count of elements. So we end up with:
for (var i=0; i < values[0].length; i++){ ... }
Using parseInt() is a good choice, and works well for the values in your spreadsheet. It can be improved, though, by ensuring that any String values have leading non-numeric values stripped first - parseInt() can then find an Integer inside a string.
function sumColumns(values) {
return JSON.stringify(values); // For debugging, just return string showing values
var sum = 0;
for(var i = 0; i < values[0].length; i++){
var input = new String(values[0][i])
.replace( /^\D+/g, ''); // Strip any leading non-digits
sum += parseInt(input);
}
return sum;
}
I'm not good with custom function because I never use them but it seems that values is not really an array...
Comments in italic :
Hmmm embarrassing ... my first though was that it had to be a 2D array but I logged val[0] in my test and it returned an 'undefined' error... I must have mistyped something at that moment... Anyway, that's why I looked for a way around handling data as a string and using split and regex.
As usual with Mogsdad's answers you have an answer and all the explanations that go with it ;-) and, as often with him too, you get a better answer than mine.
(one restriction though (#Mogsdad) your comment about non integer values could be applied to your code as well... you simply strip out any decimal value with parseInt()...:-)
That said, your use case was well described and in the limits of this example both code should work as expected, Mogsdad's one being more 'academic' and programmatically correct.
end of comment.
Using this trick below it works as expected for any input range (1 or more row and columns):
function sumCol(val) { // returns the sum of all numeric values in range
var values = val.toString().split(',');
var sum = 0;
for(var n=0;n<values.length;++n){
sum+=Number(values[n].replace(/[^0-9+.]/ig,''));
}
return sum;
}
I changed also the number extraction mode to make it more universal.

Changing values of each object in Javascript

What is the best way to add the additional path information to each javascript object? Like "assets/img/upload/" before each jpg name? That I have url="assets/img/upload/02.jpg" etc.? That would be great help!
My data right now:
[Object { url="02.jpg"},
Object { url="03.jpg"},
Object { url="09.jpg"},
Object { url="04.jpg"},
Object { url="5.jpg"}
...]
A simple for loop:
for(var i = 0; i < array.length; i++)
{
array[i].url = "assets/img/upload/" + array[i].url;
}
Suppose your array of objects is called MyArray:
for (var i = 0, LoopTimes = MyArray.length; i < LoopTimes; i++) {
MyArray[i].url = "assets/img/upload/" + MyArray[i].url;
}
Note that:
a) the opening curly brace goes on the same line as the for statement. See Crokfod on Javascript The Good Parts on youtube for the explanation. In javascript, putting the opening brace on the next line can create some weird bugs that are hard to detect.
b) I cache the length of MyArray in LoopTimes so that I don't have to evaluate the length of the array at every iteration.
If you are only going to be running this code in a modern browser, you could always consider using the map method of the Array object.
Assuming your array of objects is called "array"
array.map(function(item) {return item.url = "assets/img/upload/" + item.url;});
This runs the anonymous function, that takes an "item" in the array, and returns the modified url field, over each element of the array.
If you need your code to run on older browsers, stick with the for loops suggested by the other contributors.

JavaScript JSON compare

There are two JSON var (JSON.parse'd already)
var acc http://pastebin.com/7DyfFzTx
var sit http://pastebin.com/vnZiVaDx
My objective is to loop each var to compare acc.items.site_name with sit.items.main_site.name to see if they are equal. If they are equal, then I need to store sit.items.main_site.site_url in a variable. I am using this code:
for(i=0; i < acc.items.length;i++)
{
aname = acc.items[i].site_name;
for(i=0; i < sit.items.length;i++)
{
sname = sit.items[i].main_site.name;
if (aname == sname)
alert("same "+aname);
}
}
But the alert only logs "same Physics" . "Physics" is the first object in acc.items. This means that the loop is only comparing first acc.items but how do I make it compare the second and further on objects (e.g. "TeX - LaTeX")
Well, you can start by using a different control variable for the outer and inner loops. :)
Also, notice how you are running through every element of the second object each time you consider an element in the first object- that doesn't seem like what you want to do.
Try reviewing this posting for a more modular method:
http://jsperf.com/recursive-vs-json-object-comparison
You're using the same variable for the inner and outer loop.
Give the second for loop a different variable name than i

Categories

Resources