Dynamic condition in IF statement - javascript

I want to make condition of if statement dynamically in javascript,
check my code
var t = ['b','a']
if(t[0] !== 'a' && t[1] !== 'a'){console.log('remaining element')}
here t might be vary at any time say t = ['b','a','c'] then I need to write if condition like this
if(t[0] !== 'a' && t[1] !== 'a' && t[2] !== 'a'){console.log('remaining element')}
How can I rewirte this code efficiently?

You can use Array.prototype.every like this
if (t.every(function(currentElement) { return currentElement !== "a"; })) {
console.log('remaining element');
}
This works with arbitrary number of elements.
On older environments which do not support Array.prototype.every, you can use the plain for loop version
var flag = true;
for (var i = 0 ; i < t.length; i += 1) {
if (t[i] === "a") {
flag = false;
break;
}
}
if (flag) {
console.log('remaining element');
}

Related

Return "True" if all the characters in a string are "x" or "X" else return false

I am looking at this code challenge:
Complete the function isAllX to determine if the entire string is made of lower-case x or upper-case X. Return true if they are, false if not.
Examples:
isAllX("Xx"); // true
isAllX("xAbX"); // false
Below is my answer, but it is wrong. I want "false" for the complete string if any of the character is not "x" or "X":
function isAllX(string) {
for (let i = 0; i < string.length; i++) {
if (string[i] === "x" || string[i] === "X") {
console.log(true);
} else if (string[i] !== "x" || string[i] !== "X") {
console.log(false);
}
}
}
isAllX("xAbX");
Your loop is outputting a result in every iteration. There are two issues with that:
You should only give one result for an input, so not in every iteration; currently you are reporting on every single character in the input string.
You are asked to return a boolean result (false/true), not to have the function print something. That should be left to the caller
You could take a simpler approach though, and first turn the input string to all lower case. Now you only have to look for "x". Then take out all "x" and see if something is left over. You can check the length property of the resulting string to decide whether the return value should be false or true:
function isAllX(string) {
return string.toLowerCase().replaceAll("x", "").length == 0;
}
console.log(isAllX("xxXXxxAxx")); // false
console.log(isAllX("xxXXxxXxx")); // true
If you are confortable with regular expressions, you could also use the test method:
function isAllX(string) {
return /^x*$/i.test(string);
}
console.log(isAllX("xxXXxxAxx")); // false
console.log(isAllX("xxXXxxXxx")); // true
You can try this way.
function isAllX(str) {
let isX = true;
let newString = str.toLowerCase();
for (let i = 0; i < newString.length; i++) {
if (newString[i] !== "x") {
isX = false;
}
}
return isX;
}
console.log(isAllX("xAbX"));
console.log(isAllX("XXXxxxXXXxxx"));
You can use regex to find the same.
function allX(testString) {
return /^x+$/i.test(testString);
}
console.log(allX("xxXX"));
console.log(allX("xxAAAXX"));
Without any method if you want
function isAllX(str) {
let flag = true;
for (let i = 0; i < str.length; i++) {
if (str[i] !== "x" && str[i] !== "X") {
flag = false;
// break;
}
}
return flag;
}
console.log(isAllX("xAbX"));
console.log(isAllX("XXXxxxXXXxxx"));
console.log(isAllX("xx"));
You can try converting the string to a single case, then looping over it while checking for the condition as below
function isAllX(string) {
const newString = string.toUpperCase();
for (let i = 0; i < newString.length; i++) {
if (newString[i] !== "X") {
return false
}
}return true
}

Loop thru array to make sure criteria is met on every item

I have an array of items. I want to make sure every item meets a certain criteria.
I wrote this for loop but I'm not sure if it's the most efficient. Is there a better way to do this?
let match = 0;
for (var i = 0; i < lastPressed.length; i++) {
if (lastPressed[i].o.length === 1 && lastPressed[i].n.length === 0) {
match++;
} else {
break;
}
}
if(match === lastPressed.length) return true;
return false;
Javascript has a function just for this: Array.prototype.every.
return lastPressed.every(v => v.o.length === 1 && v.n.length === 0);
Using builtin every is the best choice here.
However, assuming you want to do it by yourself (for fun, for learning), notice that you don't have to check every item in the array. It's because the very first item that doesn't match the criteria should fail the whole process.
You just have to reverse the condition then. You don't need the count.
for (var i = 0; i < lastPressed.length; i++) {
if (!(lastPressed[i].o.length === 1 && lastPressed[i].n.length === 0)) {
return false;
}
}
return true;
It's exactly your code but the loop terminates when you find the first nonmatching element.
You could take a for ... of statement and exit early.
This approach uses a destructuring assignment and a negated condition for the check.
for (const { o, n } of lastPressed) {
if (o.length !== 1 || n.length !== 0) return false;
}
return true;

Cannot read property length null error when used with regular expressions

I'm a javascript beginner doing some CodeWars.com questions. I came across this question and I'm stuck due to a "cannot read property length null" error. I've tried to look up that error and can't find what the problem is in my program.
The assignment is:
"Check to see if a string has the same amount of 'x's and 'o's. The method must return a boolean and be case insensitive. The string can contains any char."
And this is what I've written so far:
function XO(str) {
var x = "x";
var o = "o";
var numX = str.match(/x/gi).length;
var numO = str.match(/o/gi).length;
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
}
}
if (numX === -1 && numO === -1){
return true;
}
}
XO("xoxo");
The assignment also says that if there is neither an X or an O then the program should return true.
This will not give you that error. When there are no matches, the match function returns null and you cannot get the length of null. A few extra lines solves this issue.
function XO(str) {
var x = "x";
var o = "o";
var numX = 0;
var numO = 0;
var xMatch = str.match(/x/gi);
var oMatch = str.match(/o/gi);
if (xMatch) {
numX = xMatch.length;
}
if (oMatch) {
numO = oMatch.length;
}
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
} else {
return false;
}
}
if (numX === -1 && numO === -1){
return true;
} else {
return false;
}
}
console.log(XO("ddd"));
I think you are making this problem more complex than it has to be.
All you need to do is make the string lowercase(to account for case insensitive), traverse the string, and when it finds an x, add 1 to a counter, and when you find and o, decrease 1 from the counter.
If it ends at 0, you return true, else you return false. There's no need for regexes
function XO(str){
var count = 0;
str = str.toLowerCase();
for(var i = 0; i < str.length; i++){
if(str[i] === 'x') count++;
if(str[i] === 'o') count--;
}
return count === 0 ? true : false;
}
Yes you have to check the return value of match is not null before checking the length property. However
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
}
}
looks like an infinite loop if either string contains lower case 'x' or 'o' and there are a different number of each.
More simply:
function XO(str)
{ var matchX = str.match(/x/gi);
var matchY = str.match(/o/gi);
return (matchX && matchY) ? matchX.length == matchY.length : !matchX && !matchY;
}

Javascript function to validate contents of an array

Here's what is asked:
validItems(items) – this function receives a string array of items which are to be for a customer. The function returns an empty string indicating all item codes in the array are valid; otherwise the function returns the first invalid item code in the array. All item codes must be selected from the item codes provided. They are: IT00, O144, 6A1L, 4243, O3D5, 44SG, CE64, 54FS and 4422.
This is what I've done so far:
function validItems(items) {
var error = false;
for (i = 0; i < items.length; i++) {
if (error == false) {
if (items[i] != "IT00" ||
items[i] != "0144" ||
items[i] != "6A1L" ||
items[i] != "4243" ||
items[i] != "O3D5" ||
items[i] != "44SG" ||
items[i] != "CE64" ||
items[i] != "54FS" ||
items[i] != "4422") {
error = items[i];
} else {
error = false;
}
} else {
if (error != false) {return error;} else {return "";}
}
}
}
var items = ["IT00","0144","6A1L"];
alert(validItems(items));
It keeps on returning IT00. What am I doing wrong?
What you'll notice here is that there is zero complexity. Each function below takes a couple arguments and does one simple task. It's very easy to see what each function does at first glance.
// your data
const validItems = [
"0144", "6A1L", "4243", "O3D5", "44SG", "CE64", "54FS", "4422"
];
// some reusable functions
const all = f => xs => xs.every(f);
const comp = f => g => x => f(g(x));
const neq = y => x => x !== y;
const indexOf = xs => x => xs.indexOf(x);
const elem = xs => comp(neq(-1))(indexOf(xs))
// your helpers
const validateItems = all(elem(validItems));
// test it out
console.log( validateItems(["0144", "6A1L"]) ); // true
console.log( validateItems(["0144", "CAKE"]) ); // false
You can use a simple array based test like
var validCodes = ['IT00', 'O144', '6A1L', '4243', 'O3D5', '44SG', 'CE64', '54FS', '4422'];
function validItems(items) {
for (var i = 0; i < items.length; i++) {
if (validCodes.indexOf(items[i]) == -1) {
return items[i];
}
}
return '';
}
var items = ["IT00", "O144", "6A1L"];
alert(validItems(items));
To make your code work
function validItems(items) {
var error = false;
for (i = 0; i < items.length; i++) {
console.log(items[i], error)
if (error == false) {
//need to use && since otherwise one value cann't satisfy all these conidtions
if (items[i] != "IT00" && items[i] != "0144" && items[i] != "6A1L" && items[i] != "4243" && items[i] != "O3D5" && items[i] != "44SG" && items[i] != "CE64" && items[i] != "54FS" && items[i] != "4422") {
//if current item is not matching assign it to the error and break the loop
error = items[i];
break;
//you can really return from here, not need to use the error variable also
}
}
}
//this should be outside of the loop
//if there is an errro return the error string
if (error != false) {
return error;
} else {
return "";
}
return '';
}
var items = ["IT00", "0144", "6A1L"];
alert(validItems(items));
According to your code it is correct that it is outputting IT00.
You are using the OR selector which means if the string is IT00, then it is not 0144 or 6A1L. Your intention is to exclude ALL so you are looking for values which are not IT00 AND not 0144 ANd not 6A1L, etc. etc.
use the AND:
if (items[i] != "IT00" &&
items[i] != "0144" &&
items[i] != "6A1L" &&
items[i] != "4243" &&
items[i] != "O3D5" &&
items[i] != "44SG" &&
items[i] != "CE64" &&
items[i] != "54FS" &&
items[i] != "4422") {
When you understand the basic of this logic, also try to rewrite your code. An array of allowed values is for example a bit more tidy ;-)
Your first item returns true on your if statement. If your first item is "ITOO", The first match of you make is:
items[i] != "0144"
your code then says
error = items[i]; //which is "ITOO"
and then you return
error
which is the first item "ITOO"
Your Or condition should have "==" instead of "!=".
Which means -> If "the give code" is same as "any of the recognized codes" then recognize it otherwise drop it.
Currently your condition means -> If "the given code" is not same as "any of the recognized code" then recognize it. This condition will always be true
You had some basic coding errors in your code.
I've modified your code and put in the comments where I saw room for improvement.
Basically your if else statements were redundant. If you simply exit the function by returning the faulty thing you already get the desired result.
No need to keep looping if we have found a mismatch.
In a function where you'd need to do additional checks after finding a fault you would use break and then do your logic on error if error !== false
function validItems(items) {
// create a valid items array. This will make maintaining valid item codes easier. and keep your code readable.
var valid = ["IT00","0144","6A1L","4243","O3D5","44SG","CE64","54FS","4422"];
var error = false;
for (i = 0; i < items.length; i++) {
// Type safe test. Always use 3 === isntead of == your test would have returned true on eveyrthing.
if (error === false) {
if(valid.indexOf(items[i]) === -1) {
// immedeately escape
return items[i];
} /*else {// Totally uneccesary
error = false;
}
} else {
// not needed here. this also escaped your loop after first iteration.
if (error !== false) {return error;} else {return "";}
}*/
}
// we return here because we know the loop is done then.
return error;
}
var items = ["IT00","0144","6A1L"];
alert(validItems(items));

Determine Document Order from Nodes

If I have two nodes in an HTML document, how can I tell which one comes first in HTML document order in Javascript using DOM methods?
For example,
function funstuff(a, b) {
//a and b can be any node in the DOM (text, element, etc)
if(b comes before a in document order) {
var t = b; b = a; a = t;
}
// process the nodes between a and b. I can handle this part
// when I know that a comes before b.
}
Resig to the rescue:
// Compare Position - MIT Licensed, John Resig
function comparePosition(a, b){
return a.compareDocumentPosition ?
a.compareDocumentPosition(b) :
a.contains ?
(a != b && a.contains(b) && 16) +
(a != b && b.contains(a) && 8) +
(a.sourceIndex >= 0 && b.sourceIndex >= 0 ?
(a.sourceIndex < b.sourceIndex && 4) +
(a.sourceIndex > b.sourceIndex && 2) :
1) +
0 :
0;
}
You can use the DOM function compareDocumentPosition which will return different numbers based on the two nodes' relationships:
DOCUMENT_POSITION_DISCONNECTED = 0x01;
DOCUMENT_POSITION_PRECEDING = 0x02;
DOCUMENT_POSITION_FOLLOWING = 0x04;
DOCUMENT_POSITION_CONTAINS = 0x08;
DOCUMENT_POSITION_CONTAINED_BY = 0x10;
Potentially the result could be the sum of more than one of these codes as the answer is a bitmask, but I can't imagine a situation where two of these conditions would be true at the same time. Also note that the "disconnected" result would be returned for instance with nodes that have been created but not added to the document tree yet
Rather difficult, I personally would itterate up each tree till I found a common ansester, then check which parent node(or the actual node if that low) comes first starting with firstChild and working through siblings, something like:
function OrderCheck(node1, node2){
var ar1 = [null, node1];
var ar2 = [null, node2];
for(var i = 1; ar1[i] != null; i++)
ar1[i+1]=ar1[i].parentNode;
for(var i = 1; ar2[i] != null; i++)
ar2[i+1]=ar2[i].parentNode;
ar1.reverse(); ar2.reverse(); // easier to work with.
i = 0;
while( ar1[i] === ar2[i] ){
if(ar1[i] === null)
return 0;
else
i++
}
if(ar1[i] === null)
return 2;
if(ar2[i] === null)
return 1;
if(i != 0){
var n = ar1[i-1].firstChild;
do{
if(n === ar1[i])
return 1;
if(n === ar2[i])
return 2;
}while(n = n.nextSibling);
}
return -1;// Shouldn't happen.
}
var order = OrderCheck(document.body, document.body.previousSibling);
if( order == 1){
// element 1 first
}else if(order == 2){
// element 2 first
}else{
// there was an error.
}
I did just edit this code in an attempt to fix two possible problems, I haven't tested this new edit however, so if something breaks I shall have to try again. (Edited again to fix a "doesn't even run" style bug).

Categories

Resources