javascript indexOf not working as expected with array - javascript

I am getting -1 from myarray.indexOf(element) even when element appears to be in myarray.
Here's some code snippets:
function createChangeRecord( old_array, new_array ) {
var nds = new_array.slice(0,new_array.length);
var el, idx;
if (...) {
...
} else if ( old_array.length==new_array.length ) {
for ( var i=0; i<old_array.length; i++ ) {
el = old_array[i];
idx = nds.indexOf(el);
if ( idx!=(-1) ) {
...
} else {
var a = "el: " + el + "; nds: " + nds + "; nds.indexOf(el): " + nds.indexOf(el);
alert( a );
...
}
}
...
}
...
}
The alert shows me that nds does indeed contain el but the alert should only fire when idx==-1, which should only be true when nds does not contain el.
I know I haven't given enough information to determine the specific issue in my case, but maybe someone can tell me some general reasons which might cause this behavior?
Responses to a similar question suggested using jQuery inArray() instead of indexOf, but I want to know why indexOf doesn't work. Others suggested that indexOf is for strings, not arrays, but that's not true from the online docs I can find.

Use
nds.indexOf(parseInt(el,10))
where nds is an array and el is a number (or supposed to be a number)
Edit:
From msdn:
JavaScript is a loosely typed language, which means you do not declare
the data types of variables explicitly. In many cases JavaScript
performs conversions automatically when they are needed. For example,
if you add a number to an item that consists of text (a string), the
number is converted to text.
And I guess such conversion was the reason of indexOf returning -1 because one of your array contained number and other contained string.
For example:
old_array = ["10", "20", "30"];
new_array = [10, 20, 30];
Below is my attempt to answer your questions:
Why indexOf() does not work?
It does work and I guess it worked in your case too.
It returned -1 when el string, e.g "100", was not found in an array of numbers, e.g. nds=[100,200] which is true. Because "100" string is not same as 100 number.
Does indexOf() work with strings, array, etc?
Yes, indexOf() works with array (of number, string, or any object), as well as with string. But you have to make sure to check with same types.
What does parseInt() do?
To avoid unintended comparison of a number with a string, we can use parseInt(), for example parseInt("123", 10) returns the number 123.
The second argument 10 is called radix. A number (from 2 to 36) that represents the numeral system to be used.
Summary:
> "javascript is awesome".indexOf('v')
2
> [10, 20, 30].indexOf("20")
-1
> [10, 20, 30].indexOf(20)
1
> [10, 20, 30].indexOf( parseInt("20", 10) )
1
> typeof (100)
number
> typeof ("100")
string
> typeof( parseInt( "100", 10))
number
> parseInt( "100", 10)
100
> parseInt("100", 2)
4
> parseInt(11.3, 10)
11
> parseInt(11.3, 2)
3
> [10.3, 11.3, 12.3, 11].indexOf( parseInt(11.3, 10) )
3
To see all of above in action:
check the below code snippet but be aware of alert(); and console.log(); when you run it.
function createChangeRecord( old_array, new_array ) {
var nds = new_array.slice( 0, new_array.length ); // this seems to be redundant
var el, idx, msg;
if ( old_array.length == new_array.length ) {
for ( var i=0; i<old_array.length; i++ ) {
el = old_array[i];
idx = nds.indexOf(el);
if ( idx != -1 ) {
msg = "Found: el: " + el + "; nds: " + nds + "; nds.indexOf(el): " + idx + "\n typeof el: " + (typeof el) + "; typepf nds[" + i + "]: " + (typeof nds[i]);
} else {
msg = "Not Found: el: " + el + "; nds: " + nds + "; nds.indexOf(el): " + idx + "\n typeof el: " + (typeof el) + "; typepf nds[" + i + "]: " + (typeof nds[i]);
}
console.log( msg );
alert( msg );
}
}
else {
var err = 'Array lengths are not same';
console.log( err );
alert( err );
}
}
// this will work
var old_array_g = [ 10, 20 ];
var new_array_g = [ 10, 20 ];
createChangeRecord( old_array_g, new_array_g );
// this will not work
var old_array_g = [ "10", "20" ];
var new_array_g = [ 10, 20 ];
createChangeRecord( old_array_g, new_array_g );
// Yes: indesOf works with strings too
var withStrings = "'javascript is awesome'.indexOf('v'): " + "javascript is awesome".indexOf('v');
console.log( withStrings );
alert( withStrings );
// parseInt() returns a number or say integer
var usingParse = "typeof(123): " + typeof( 123 ) + "; typeof( parseInt('123', 10) ): " + typeof ( parseInt('123', 10) ) + "; typeof ('123'): " + typeof('123');
console.log( usingParse );
alert( usingParse );
// parseInt() with base 2
var parseBase2 = "parseInt( '100', 2 ): " + parseInt('100', 2) + "; parseInt( '100' , 10): " + parseInt('100', 10);
console.log( parseBase2 );
alert( parseBase2 );

indexOf does work and does do what you say it does.
For example (to demonstrate from a console):
> a = [1,2,3,4,5,6,7,8];
[1, 2, 3, 4, 5, 6, 7, 8]
> b = a.slice(0,a.length);
[1, 2, 3, 4, 5, 6, 7, 8]
> b.indexOf(a[4])
4
If you're getting this error, it might mean you've mixed up source and destination (the array before the dot is the one being searched), or you have another subtle programming error (like you aren't comparing the array you think you're comparing).

When you use indexOf(value) on an Array, it returns you the index of the value in the array.
> var testArray = ["a","b","c"];
> testArray.indexOf(1)
-1
> testArray.indexOf("b")
1
> testArray.indexOf("c")
2
> testArray = [10,12,3];
> testArray.indexOf(12)
1
You should check what you get from el with a typeof(el)

Taking the top example:
where you have idx=nds.indexOf(el)
replace it with idx=nds.indexOf(''+el+'')
It solved a similar problem for me within the thing I'm working on, but I stumbled on it messing around looking for a solution.
Whether it's stable in all circumstances is something I can't answer.

If your search array contained numbers, and you want to search for items like 2 or "2"
nds = [1, 2, 3, 4, 5];
This works (Add plus)
nds.indexOf(+el)

Related

min value from a string contains number, character and space

Encountered a string, contains both number as well Character with space like
" 7, 4, B, 9"
I am trying to get minimum value out of it.
By converting into an array and using Min function we can get the value out of it.
When we are having string and space with it, how to do it in one go.
Please suggest me
let myStr = ' 7, 4, B, 9'
Math.min.apply( null, myStr.match(/\d+/g) )
First we create the array using match with a simple regex. Then we apply the Math.min function to each element of the array.
function doTheThing(arr) {
return arr.filter(function(item){
return typeof item === "number";
}).reduce(function(p, c) {
return Math.min(p, c);
});
}
document.write(doTheThing([5, 6, "A", 61, "B"]));
I instead came up with this example if it happens to suit the needs:
search = " 7, 4, B, 9";
min = 9999; search.split(",").forEach( function (val) {
val = val.replace(/^\s+/,'').replace(/\s+$/,'');
return Number(val) == val
? (min = min < val ? min : val)
: (String(val).charCodeAt(0) > min
? min
: String(val).charCodeAt(0) )
} );
console.log(min)
It should work just fine in the browser console.

JQuery foreach chunk 2 and 2

So I have this array:
Mike
Blue
Jakob
Red
Luis
Orange
executing with this JQuery code:
$.each( arr, function( index, value ){
$( ".div" ).append( "" + value + "" );
}
});
I would like the each loop to jump every second value. So that the loop would create something like:
Mike - Blue
Jakob - Red
Luis - Orange
Can anyone point me in the right direction?
Instead of using $.each, you can just use a normal for loop and increment by 2 instead of 1.
for(var i = 0; i < arr.length; i += 2){
$(".div").append(arr[i] + ' - ' + arr[i+1]);
}
You can use javascript's modulo (%) operator and jQuery's $.each's argument of index
$.each( arr, function( index, value ){
if (index%2 == 0) { //0, 2, 4 (mike, jacob, luis)
$( ".div" ).append( "" + value + "" );
}
});
Modulo gives the remainder when divided by the given number. For example, 6%2 does 6/2, then takes the remainder. Since 2 goes into six exactly 3 times, the modulo is 0, as there is no remainder.
Thus, any even number will return 0 from a modulo with 2. We can use this to check if the index is even (0, 2, 4, 6), which will be every other iteration
This should work
$.each( arr, function( index, value ){
var ival = index+1; // index always starts from 0 So we are adding 1 to start the counter from 1
if(ival%2 == 0){ // %2 is the modulus of 2, If the value is 0, The counter is now an even number, other wise its an odd number
$( ".div" ).append( " - " + value + "" );
}else{
$( ".div" ).append( "" + value + "" );
}
});
You could actually reverse your thinking, and append the result of a mapping
$( ".div" ).append(arr.map(function(x,i) {return i%2 ? x+' - '+arr[i-1] + '<br/>' : null}))
var arr = [
"Mike",
"Blue",
"Jakob",
"Red",
"Luis",
"Orange"
];
$( ".div" ).append(arr.map(function(x,i) { return i%2 ? x+' - '+arr[i-1] + '<br/>' : null }));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="div"></div>

Find all permutations of a set of numbers and operators

I was given a code challenge to do that was related to recursion and was unable to complete it. My experience with these types of questions is very slim and this one just stumped me. Could any of you help me out just for my own education, as I've already failed the challenge?
The description:
Given a string of numbers and operators, print out all the different ways you can add parentheses to force the order of operations to be explicit, and the result for running the operations in that order.
Assume:
No weird inputs, everything is separated by one space.
Supported operators are +, *, -, = (for the = operator, if the values are the same return 1, otherwise return 0)
Print your results sorted numerically
Don't worry about the input expression size being too large
Your code should be written in javascript
Don't use eval or external libraries
Example:
node test.js "2 - 1 - 1"
((2-1)-1) = 0
(2-(1-1)) = 2
node test.js "2 * 3 - 4 * 5";
(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10
node test.js "2 + 2 = 2"
((2+2)=2) = 0
(2+(2=2)) = 3
This is where I'm at so far. I'm far from getting the right output, but I feel like the logic is starting to get there. I've adapted this code from a similar, but different question.
var args = process.argv.slice(2)[0].split(" "),
numberOfOperators = 0;
args.forEach(function(val, index, array) {
if (isNaN(val)) {
++numberOfOperators;
}
});
args = args.join("");
var recurse = function(openParenCount, closeParenCount, input, pointer) {
if (openParenCount === 0 && closeParenCount === 0) {
console.log(input + "\n");
}
if (openParenCount > 0) {
input = input.slice(0, pointer) + "(" + input.slice(pointer, input.length);
recurse(openParenCount - 1, closeParenCount + 1, input, pointer+1);
}
if (closeParenCount > 0) {
input = input.slice(0, pointer+openParenCount+3) + ")" + input.slice(pointer+openParenCount+3, input.length+1);
recurse(openParenCount, closeParenCount - 1, input, pointer+3);
}
}
recurse(numberOfOperators, 0, args, 0);
a little hint:
var AP = [];
var input = process.argv.slice(2)[0];
var args = input.replace(/\s+/g, "").split(/([^\d\.]+)/g);
recurse(args, []).forEach(function(v){ console.log(v); });
function recurse(arr, into){
if(arr.length === 1){
into.push(arr[0]);
}else{
for(var i=0, j=arr.length-2; i<j; i+=2){
recurse(
AP.concat(
arr.slice(0, i),
"(" + arr.slice(i, i+3).join(" ") + ")",
arr.slice(i+3)
),
into
)
}
}
return into
}
This Implementation still has a few "bugs", and these by intent; I'm not going to do your "homework".
If you have more than 2 operators in your Equasion, the result will contain duplicates, 2nd It is not sorted, and since it is just splitting and concatenating strings, it can't compute any result.
But it shows you a way how you can implement the recursion.

Strange method result using Math.round

When this method is called with
knownScore = 70,
newScore = 70,
depth = 1,
it returns 3535 !!!!!
How is this possible?
this.weightedAvg = function(depth, knownScore, newScore) {
if ((knownScore > 100) || (knownScore < -100)) return newScore;
else return Math.round((depth*knownScore + newScore)/(depth + 1));
};
When called with values 35, 70, 2, it returns 2357!
Any help please?
The value of newScore you're passing to the function is a string. You should make sure they are all numbers. This code will work (notice the + sign that converts newScore to a number):
this.weightedAvg = function(depth, knownScore, newScore) {
if ((knownScore > 100) || (knownScore < -100)) return newScore;
else return Math.round((depth*knownScore + +newScore)/(depth + 1));
};
More details:
70 + '70' // this is string concatenation instead of addition, results in 7070
The result is converted to a number when it is divided by 2:
'7070'/2 // converts to number, resulting in 3535
You need to parse your var to number like this:
var number1 = Number(n);
You are passing string so he do "2" + "35" + "70" instead of 2 + 35 + 70 !

Javascript: How to retrieve the number of decimals of a *string* number?

I have a set of string numbers having decimals, for example: 23.456, 9.450, 123.01... I need to retrieve the number of decimals for each number, knowing that they have at least 1 decimal.
In other words, the retr_dec() method should return the following:
retr_dec("23.456") -> 3
retr_dec("9.450") -> 3
retr_dec("123.01") -> 2
Trailing zeros do count as a decimal in this case, unlike in this related question.
Is there an easy/delivered method to achieve this in Javascript or should I compute the decimal point position and compute the difference with the string length? Thanks
function decimalPlaces(num) {
var match = (''+num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
if (!match) { return 0; }
return Math.max(
0,
// Number of digits right of decimal point.
(match[1] ? match[1].length : 0)
// Adjust for scientific notation.
- (match[2] ? +match[2] : 0));
}
The extra complexity is to handle scientific notation so
decimalPlaces('.05')
2
decimalPlaces('.5')
1
decimalPlaces('1')
0
decimalPlaces('25e-100')
100
decimalPlaces('2.5e-99')
100
decimalPlaces('.5e1')
0
decimalPlaces('.25e1')
1
function retr_dec(num) {
return (num.split('.')[1] || []).length;
}
function retr_dec(numStr) {
var pieces = numStr.split(".");
return pieces[1].length;
}
Since there is not already a regex-based answer:
/\d*$/.exec(strNum)[0].length
Note that this "fails" for integers, but per the problem specification they will never occur.
You could get the length of the decimal part of your number this way:
var value = 192.123123;
stringValue = value.toString();
length = stringValue.split('.')[1].length;
It makes the number a string, splits the string in two (at the decimal point) and returns the length of the second element of the array returned by the split operation and stores it in the 'length' variable.
Try using String.prototype.match() with RegExp /\..*/ , return .length of matched string -1
function retr_decs(args) {
return /\./.test(args) && args.match(/\..*/)[0].length - 1 || "no decimal found"
}
console.log(
retr_decs("23.456") // 3
, retr_decs("9.450") // 3
, retr_decs("123.01") // 2
, retr_decs("123") // "no decimal found"
)
I had to deal with very small numbers so I created a version that can handle numbers like 1e-7.
Number.prototype.getPrecision = function() {
var v = this.valueOf();
if (Math.floor(v) === v) return 0;
var str = this.toString();
var ep = str.split("e-");
if (ep.length > 1) {
var np = Number(ep[0]);
return np.getPrecision() + Number(ep[1]);
}
var dp = str.split(".");
if (dp.length > 1) {
return dp[1].length;
}
return 0;
}
document.write("NaN => " + Number("NaN").getPrecision() + "<br>");
document.write("void => " + Number("").getPrecision() + "<br>");
document.write("12.1234 => " + Number("12.1234").getPrecision() + "<br>");
document.write("1212 => " + Number("1212").getPrecision() + "<br>");
document.write("0.0000001 => " + Number("0.0000001").getPrecision() + "<br>");
document.write("1.12e-23 => " + Number("1.12e-23").getPrecision() + "<br>");
document.write("1.12e8 => " + Number("1.12e8").getPrecision() + "<br>");
A slight modification of the currently accepted answer, this adds to the Number prototype, thereby allowing all number variables to execute this method:
if (!Number.prototype.getDecimals) {
Number.prototype.getDecimals = function() {
var num = this,
match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
if (!match)
return 0;
return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
}
}
It can be used like so:
// Get a number's decimals.
var number = 1.235256;
console.debug(number + " has " + number.getDecimals() + " decimal places.");
// Get a number string's decimals.
var number = "634.2384023";
console.debug(number + " has " + parseFloat(number).getDecimals() + " decimal places.");
Utilizing our existing code, the second case could also be easily added to the String prototype like so:
if (!String.prototype.getDecimals) {
String.prototype.getDecimals = function() {
return parseFloat(this).getDecimals();
}
}
Use this like:
console.debug("45.2342".getDecimals());
A bit of a hybrid of two others on here but this worked for me. Outside cases in my code weren't handled by others here. However, I had removed the scientific decimal place counter. Which I would have loved at uni!
numberOfDecimalPlaces: function (number) {
var match = ('' + number).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
if (!match || match[0] == 0) {
return 0;
}
return match[0].length;
}
Based on Liam Middleton's answer, here's what I did (without scientific notation):
numberOfDecimalPlaces = (number) => {
let match = (number + "").match(/(?:\.(\d+))?$/);
if (!match || !match[1]) {
return 0;
}
return match[1].length;
};
alert(numberOfDecimalPlaces(42.21));
function decimalPlaces(n) {
if (n === NaN || n === Infinity)
return 0;
n = ('' + n).split('.');
if (n.length == 1) {
if (Boolean(n[0].match(/e/g)))
return ~~(n[0].split('e-'))[1];
return 0;
}
n = n[1].split('e-');
return n[0].length + ~~n[1];
}

Categories

Resources