Javascript function to validate contents of an array - javascript

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));

Related

Bubble Sort in never ending loop

I have the following data:
I basically want the 5,6,7 records to be at the very top of the list ordered by eta. The rest I am OK with as they stand. since they do not realy have an eta.
My JS function :
bubbleSortETA : function(array) {
var swapped;
do {
swapped = false;
for(var i = 0; i < array.length; i++) {
console.log('array[i]');
console.log(array[i]);
console.log('array[i+1]');
console.log(array[i+1]);
var thisRowEta;
var nextRowEta;
if (array[i] && typeof(array[i].eta) != "undefined"){
thisRowEta = array[i].eta;
}else{
thisRowEta = 1000; //so it appears at the bottom???
}
if (array[i+1] && typeof(array[i+1].eta) != "undefined"){
nextRowEta = array[i+1].eta;
}else{
nextRowEta = 1000;
}
if(array[i] && array[i + 1] && typeof(array[i].walkInDetails) != "undefined" && typeof(array[i+1].walkInDetails) != "undefined" && (thisRowEta != nextRowEta)){
this.swap(array, i, i + 1);
console.log('we swapped...');
swapped = true;
}
}
} while(swapped);
console.log(array);
return array;
}
It goes into this never ending loop. I have tried looking at output statements but am unable to understand why it is going into infinite loop.
Any tips?

difference between regular loop and splice in angular filter?

Below is a fragment of code in one of my angular filters which i am using with bootstrap pagination.
//first statement
let ret = [];
for (let i = from; i < limit + from; i++) {
if (typeof items[i] !== typeof undefined) {
ret.push(items[i]);
}
}
//second statement
ret = items.splice(from, limit);
Using the first statement works as expected without any error while the second one results in an infinite digest loop.
What's the difference?
Edit : Full code below (as requested by T.J. Crowder)
filter('limitMe',function () {
return function (items,limit, from) {
if(
typeof items == typeof undefined ||
typeof limit == typeof undefined ||
typeof from == typeof undefined
){
return items;
}
let len = items.length;
if(len == 0){
return items;
}
if(limit > len){
limit = len;
from = 0;
}else if(len < from + limit){
limit = len - from;
}
let ret = [];
for(let i = from; i < limit + from; i++){
if(typeof items[i] !== typeof undefined){
ret.push(items[i])
}
}
/*return items.filter(function (row) {
return typeof row !== typeof undefined;
}).splice(from, limit);*/
return ret;
}
})
The two code samples do completely different things:
The first copies non-undefined, non-missing entries in the range from to limit + from into ret, also leaving them in items.
The second removes entries from items and puts them in ret (even if those entries are undefined or missing).
So after the first, items still has the entries in it. After the second, it doesn't.
Separately, the second will take undefined entries from items if they're in range, whereas the second will skip them.
If you post an MCVE, we can probably help you understand why those make for an infinite digest loop, but they're pretty major differences (particularly the first), so...

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;
}

Dynamic condition in IF statement

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');
}

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