Javascript - dont compare if condition met - javascript

I have this script for my html table which colors the cells in column row by row:
$(document).ready( function () {
var table, aP, rtvP, mmP, meP;
table = document.getElementById('productTable');
for (i = 1; i < table.rows.length; i++) {
var rowCells = table.rows.item(i).cells;
if (rowCells[3].firstChild.data !== '—') {
aP = parseFloat(rowCells[3].firstChild.data);
} else {
aP = 0;
}
if (rowCells[5].firstChild.data !== '—') {
rtvP = parseFloat(rowCells[5].firstChild.data);
} else {
rtvP = 0;
}
if (rowCells[7].firstChild.data !== '—') {
mmP = parseFloat(rowCells[7].firstChild.data);
} else {
mmP = 0;
}
if (rowCells[9].firstChild.data !== '—') {
meP = parseFloat(rowCells[9].firstChild.data);
} else {
meP = 0;
}
console.log(aP, rtvP, mmP, meP);
if (aP > rtvP || mmP || meP) {
rowCells[3].bgColor = 'red';
} else if (aP === rtvP || mmP || meP) {
rowCells[3].bgColor = 'yellow';
} else {
rowCells[3].bgColor = 'green';
}
}
})
I know that is a little monster, but the only thing I miss is that, there should be no comparison for value if that value = 0. Ex. If aP = 100, rtvP = 150, mmP = 0, meP = 50, value of mmP should be skipped in comparison. Is there easy way to do that? I don't want to make another spaghetti of IFs

You could try converting one of those instances to a proper function:
function convertP(value) {
if (value !== '—') {
return parseFloat(value);
}
return 0;
}
Then you can call it like:
meP = convertP(rowCells[9].firstChild.data);
Where you can augment that convertP function to be "smarter" and handle different cases later.
Now for your comparison problem you probably want to store these converted values into an array instead of as a bunch of unrelated variables, like:
var points = [ ];
[ 3, 5, 7, 9 ].forEach(function(i) {
points.push(convertP(rowCells[i].firstChild.data));
});
Where now you have all of them in one neat, tidy container. You can then compare them quickly by doing something like:
var diffs = [ ];
points.forEach(function(p) {
diffs.push(aP - p);
});
The key thing to remember here is that floating point values are often approximations so it's important to not depend on them being precisely equal. 1.0 + 2.0 does not necessarily === 3.0. There's going to be a tiny amount of deviation due to floating point quirks, so go with +/- some tiny value, even if that value is 0.000001.
Now you can identify your color condition with a function:
function colorCondition(aP, points) {
var state = 'green';
var epsilon = 0.000001;
points.forEach(function(p) {
if (aP > (p + epsilon)) {
state = 'red';
}
else if (aP > (p - epsilon)) {
state = 'yellow';
}
});
return state;
}
Now you have a generic solution that can work with N inputs. This is the goal of programming when you're trying to adhere to the Zero, One or Infinity Rule.

One of the ways to put a prerequisite condition in if is using the logical AND operator: &&.
For your variables it will be something like:
if (mmP!=0 && mmP>aP){}
This way if mmP is 0, first condition will return false and second condition won't be processed.
You can enforce a condition without making another spaghetti of IFs.
I'm not sure I understood your use case, so if that does not work for you just comment it.

Related

How to convert this C# scripts to Javascript

I have a C# script like below:
public List<MazePath> BreakIntoConnectedPaths()
{
List<MazeVertex> remainVertices = new List<MazeVertex>(vertices);
List<MazePath> paths = new List<MazePath>();
while (remainVertices.Count > 0)
{
MazePath path = new MazePath();
path.entrancePosition = entrancePosition;
path.exitPosition = exitPosition;
VisitCell(path, remainVertices.First(), null, remainVertices);
paths.Add(path);
//Store the coordinate for entrance and exit
}
return paths;
}
void VisitCell(MazePath path, MazeVertex ver, MazeVertex parent, List<MazeVertex> remainVertices)
{
remainVertices.Remove(ver);
path.Add(ver);
for (int i = 0; i < ver.connectVertices.Count; i++)
{
MazeVertex ver2 = ver.connectVertices[i];
if (ver2 != parent)
{
VisitCell(path, ver2, ver, remainVertices);
}
}
}
I want to convert it to javascript as below
BreakIntoConnectedPaths = function() {
var remainVertices = _.cloneDeep(this.vertices);
var paths = [];
while (remainVertices.length > 0) {
var path = new Path();
path.entrancePos = this.entrancePos;
path.exitPos = this.exitPos;
this.VisitCell(path, remainVertices[0], null, remainVertices);
paths.push(path);
// Store the coordinate for entrance and exit
}
return paths;
}
VisitCell = function(path, vertex, parentVertex, remainVertices) {
_.remove(remainVertices, function(v) {
return v.x === vertex.x && v.z === vertex.z;
});
path.Add(vertex);
for (var i = 0; i < vertex.connectVertices.length; i++) {
var connectedVertex = vertex.connectVertices[i];
// if (parentVertex && (connectedVertex.x !== parentVertex.x || connectedVertex.z !== parentVertex.z)) {
if(parentVertex && _.isEqual(connectedVertex, parentVertex)) {
VisitCell(path, connectedVertex, vertex, remainVertices);
}
}
}
The _ symbol here is lodash sign.
After I convert to javascript code, the behavior of these functions is difference with the C# one. With the same vertices data, the paths array had returned with difference size.
Thanks you for reading and pls help me if you see my mistake here.
In the C# version, your VisitCell function has a condition that says if(ver2 != parent), but in the JS version you check that they are equal instead of not equal.
Also, that condition would never pass any way because in your first call to that function you pass in null for the parent, but in that condition you check that the parent is "truthy".
Lodash's isEqual can handle null values, so I'm not sure why you're checking if the parent is truthy there. Perhaps you meant to do this?
if(!_.isEqual(connectedVertex, parentVertex)) {
There are several ways to improve your JavaScript code. When transpiling code, it is better to not copy/paste and fix, but to rewrite using the target language instead.
I would prefer to have this written, for example:
var vertices;
var entrancePos;
var exitPos;
function Path(entrancePos, exitPos){
this.entrancePos = entrancePos;
this.exitPos = exitPos;
this.Add = function() {
// your Add() code here
}
}
function breakIntoConnectedPaths() {
var remainingVertices = _.cloneDeep(vertices);
var paths = [];
while (remainVertices.length) {
var path = new Path(entrancePos, exitPos);
visitCell(path, remainingVertices.shift());
// Store the coordinate for entrance and exit
paths.push(path);
}
return paths;
}
function visitCell(path, vertex, parentVertex) {
path.Add(vertex);
for (var i = 0; i < vertex.connectVertices.length; i++) {
var connectedVertex = vertex.connectVertices[i];
if(_.isEqual(connectedVertex, parentVertex)) {
visitCell(path, connectedVertex, vertex);
}
}
}
Keep in mind that the variables vertices, entrancePos, exitPos and Path are not available to me on your C# code, so I only declare them on JavaScript. Implement them as you may.
Does that fix it, by the way?

Select random Integers from 2 arrays until condition is true

I wonder what's the most efficient way to write a function that takes two arrays of random integers and terminates when a pair of matching Integers is found.
In the following example there are two arrays, one larger then the other.
The larger array contains the potential dividents, the smaller array the divisors.
I'd like the function to calculate until it has found a pair of divident and divisor that are divisible without remainder.
EXAMPLE:
var listDivident = _.shuffle(_.range(1, 101));
var listDivisor = _.shufle(_.range(1, 11));
randomMatch = function (listDivident, listDivisor) {
/* until ((listDivident % listDivisor !== "undefined")
&& (listDivident % listDivisor === 0) {
...
}
*/
return {
matchDivident: matchDivident,
matchDivisor: matchDivisor
};
};
Is there something like an "until" function or construct in JS?
Thanks for your help!
Vin
Unless your arrays are very large, you can simply generate all valid pairs first and then pick a random one:
var pairs = [];
_.each(listDivident, function(a) {
_.each(listDivisor, function(b) {
if(!(a % b))
pairs.push([a, b])
})
});
result = _.shuffle(pairs)[0];
What you call "until" can be achieved by looping until you find what you need:
var listDivident = _.shuffle(_.range(1, 101));
var listDivisor = _.shufle(_.range(1, 11));
randomMatch = function (listDivident, listDivisor) {
var i = 0,
found = false,
dividentLength = listDivident.length,
divisorLength = listDivisor.length,
matchDivident = null,
matchDivisor = null;
while (!found && i < dividentLength && i < divisorLength) {
if (listDivident[i] % listDivisor[i] === 0) {
matchDivident = listDivident[i];
matchDivisor = listDivisor[i];
found = true;
} else {
i++;
}
}
return {
matchDivident: matchDivident,
matchDivisor: matchDivisor
};
};
EDIT: After that, just call the randomMatch() with the whole arrays:
alert(randomMatch(listDivident, listDivisor));

Efficient way to handle JS function ordering

I'm fairly new to JS and am still slightly confused, by the ordering and nesting of JS functions. I have a script that I want to occur in a specific way. The problem a criteria can be left blank by a user. Im trying to say if the variable length is greater than zero run the callback, but then move into the code that occurs under the next two if statements. I know there must be a more efficient method for this, but for the life of me I can't think of one besides placing all the other code under each different if/else statement.
var lst = []
var lst2 = []
var lst3 = []
alert(cityu);
alert(dateu);
alert(numberu);
d3.csv("kyle.csv", function (d) {
return {
city: d.from,
number: d.phone_number,
date: d.from_date
};
}, function (error, rows) {
if (dateu.length > 0) {
for (var i = 0; i < rows.length; i++) {
if (rows[i].date === dateu) {
lst.push(rows[i]);
console.log(rows[i]);
}
}
} else {
if (cityu.length > 0) {
for (var i = 0; i < lst.city.length; i++) {
if (lst.city[i] === cityu) {
lst2.push(lst[i]);
console.log(lst2);
}
}
} else {
if (numberu.length > 0) {
for (var i = 0; i < rows.length; i++) {
if (lst.number[i] === numberu) {
lst3.push(lst2[i]);
console.log(lst3);
}
}
}
}
}
})
};
Here you can see that if the dateu variable has length greater than zero the rows in a csv matching that user entered criteria will be pushed to the array "lst". Obviously it currently doesn't move into the next callback under, it will only do this if "dateu" equalled zero.
One other issue with my script is that at each if statement I hope to reduce my original input based on the user entered parameters. For example a user might enter "seattle" the variable "city" will now equal seattle and only rows containing Seattle as their city will be kept in the array that rows[i] is pushed to.
Every piece of user input shown here:
alert(cityu);
alert(dateu);
alert(numberu);
will have the same affect on the dataset, each time reducing the number of rows included.
The problem specifically is that each if statement relies on the array from the previous callback.
Your code redone a little - I've removed the else blocks, because you want to do each loop regardless of the previous loop
if(condition1) {
do something
}
else {
do something else
}
from that, if the first condition is met, the else block wont get executed
if(condition1) {
do something
}
if(condition2) {
do something else
}
In this case, do something else only relies on condition2 being true, consition1 is irrelevant
var lst = []
var lst2 = []
var lst3 = []
alert(cityu);
alert(dateu);
alert(numberu);
d3.csv("kyle.csv", function(d) {
return {
city: d.from,
number: d.phone_number,
date: d.from_date
};
}, function(error, rows) {
var i;
if (dateu.length > 0) {
for (i = 0; i < rows.length; i++) {
if (rows[i].date === dateu) {
lst.push(rows[i]);
console.log(rows[i]);
}
}
}
if (cityu.length > 0) {
for (i = 0; i < lst.city.length; i++) {
if (lst.city[i] === cityu) {
lst2.push(lst[i]);
console.log(lst2);
}
}
}
if (numberu.length > 0) {
for (i = 0; i < rows.length; i++) {
if (lst.number[i] === numberu) {
lst3.push(lst2[i]);
console.log(lst3);
}
}
}
});
};
One minor inconsequential change, moved the declaration of var i to the top of the function block, because technically you were declaring it three times, and jslint/jshint would complain - though nothing would break (yet)
I'm still not completely sure on your logic, but looking at Tiny Giant's gist, it seems like there are only three combinations:
1) Only dateu exists.
2) dateu and cityu exist.
3) dateu, cityu, and numberu exist.
So you don't care about the condition where dateu and numberu exist, but cityu is empty, right?
Okay, I reread your code. It seems like you have rows, and you have three possible filters. Filter rows based on AND, for example cityu AND dateu.
If so, here's a giant refactor. Just as a note, there may be some JavaScript errors because I had no way of testing this. But the code is fairly simple and straightforward:
var lst = [] // I'm not using these.
var lst2 = []
var lst3 = []
alert(cityu);
alert(dateu);
alert(numberu);
var getActiveFilters = function() {
// Edit possibleFilters as necessary.
// the key should reflect the header of the column
// and the value is a variable referring to the user-inputted string
var possibleFilters = {
'date': dateu,
'city': cityu,
'number': numberu
};
var activeFilters = {};
for (key in possibleFilters) {
if (possibleFilters[key].length > 0) {
activeFilters[key] = possibleFilters[key];
}
}
return activeFilters;
}
// just made this into a function to get it out of the callback
var functionAfterCsv = function(rows) {
var activeFilters = getActiveFilters();
var filteredList = [];
var addRow = false;
for(i = 0; i < rows.length; i++) {
// see if the current row matches all the filters present
for (key in activeFilters) {
if (rows[i][key] === activeFilters[key]) {
addRow = true;
} else {
addRow = false;
// if the row doesn't meet one of the conditions,
// there's no need to check the rest
break;
}
}
if (addRow) {
filteredList.push(row[i]);
}
}
return filteredList;
};
d3.csv("kyle.csv", function (d) {
return {
city: d.from,
number: d.phone_number,
date: d.from_date
};
}, function (error, rows) {
functionAfterCsv(rows);
})
});
If you're filtering using OR, then you'll need to change your comparison to something like this:
for (key in activeFilters) {
if (rows[i][key] === activeFilters[key]) {
addRow = true;
break; // if one is true, that's good enough for an OR
} else {
addRow = addRow || false;
}
}
if (addRow) {
filteredList.push(row[i]);
// reset addRow for the next row
addRow = false;
}
Hope this was closer to your intended logic!

Create 3D dimensional array

In Javascript, I don't see any tutorials clearly explain how to create like
MyItems[Row][Index][categories]
so that
MyItems[0][0][0]=1
MyItems[1][0][0]='stock'
MyItems[5][1][0]='pending'
My use case is each Index will contain different value which is integer or string.
What is the best way to avoid error when accessing MyItems[0][1][0] that has no value?
Because JS doesn't have actual multidimensional arrays, but instead merely have nested arrays that don't necessarily form a rectangular structure, you'd need to check for each nested array first. A simple "truthy" test would be fine.
if (myItems[0] && myItems[0][0])
myItems[0][0].push(1);
If you wanted to create the arrays that aren't there, then you can do that like this:
if (!myItems[0])
myItems[0] = [];
if (!myItems[0][0])
myItems[0][0] = [];
myItems[0][0].push(1);
Of course this assumes that the first and second levels should always be arrays, and only the third level will hold the actual values. You'll need to adjust it if that's not the case.
Also, a function would be a good idea to get rid of the repetition.
function addNested(outer, idx1, idx2, idx3, value) {
if (!outer[idx1])
outer[idx1] = [];
if (!outer[idx1][idx2])
outer[idx1][idx2] = [];
outer[idx1][idx2][idx3] = value;
}
addNested(myItems, 1, 0, 0, 'stock');
This is how you'd make a 3D array, but I'd recommend against mixing data types in your array, that's not exactly a common or standard practice.
// just filler stuff, ignore the body of this function
function getStringOrNumber(row, col, cat) {
var thing = row * cols * cats + col * cats + cat;
return Math.random() < .5 ? thing : thing.toString();
}
// something to deal with each value
function doSomething(value) {
switch (typeof value) {
case 'string':
// logic for string type
break;
case 'number':
// logic for number type
break;
default:
// unexpected?
break;
}
}
// here's how you make your 3D array
var rows = 10,
cols = 10,
cats = 10,
array3d = new Array(rows),
i, j, k;
for (i = 0; i < rows; i++) {
array3d[i] = new Array(cols);
for (j = 0; j < cols; j++) {
array3d[i][j] = new Array(cats);
for (k = 0; k < cats; k++) {
array3d[i][j][k] = getStringOrNumber(i, j, k);
doSomething(array3d[i][j][k]);
}
}
}
If you want to check whether an index exists on the 3d array, try a function like this:
function setValue(array3d, row, col, cat, value) {
if (array3d[row] && array3d[row][col] && array3d[row][col][cat]) {
array3d[row][col][cat] = value;
} else {
throw new RangeError("Indices out of range");
}
}
If you were to allocate each array at each index in a breadth-first pattern before accessing any of it, then this would work without any special handling.
However, as you've correctly recognized, if you want to be able to access indexes that may not have been allocated yet, this won't work.
Actually, to be more specific, you are allowed to attempt to read an index outside the length of an array, in which case you'll get undefined. The problem is that if you get undefined for the first or second depth, then an attempt to index that undefined value will fail.
Thus, to prevent this error, you must guard against undefined first- or second-depth indexes.
The best way to do this is to write a class that provides a getter and setter that automatically take care of the special handling requirements. Here's an example of such a class, defined using the prototype pattern:
(function() {
var Array3D = function() {
this.data = [];
};
Array3D.prototype.get = function(r,c,z) {
if (this.data.length <= r) return undefined;
if (this.data[r].length <= c) return undefined;
return this.data[r][c][z];
};
Array3D.prototype.set = function(r,c,z,v) {
if (this.data.length <= r) this.data[r] = [];
if (this.data[r].length <= c) this.data[r][c] = [];
this.data[r][c][z] = v;
return this;
};
window.Array3D = Array3D;
})();
var a = new Array3D();
alert(a.get(0,0,0)); // undefined, no error
a.set(0,0,0,'x');
alert(a.get(0,0,0)); // 'x'
a.set(234,1234,342,'y');
alert(a.get(234,1234,342)); // 'y'
alert(a.get(0,1,0)); // undefined, no error
alert(a.get(12341234,243787,234234)); // undefined, no error
Since this completely differs from my other answer, I thought it would be helpful to suggest another approach using nested sparse arrays which could be implemented using associative arrays or objects. Try this:
// N-dimensional array
function ArrayND() {
// nothing to do here, seriously
}
ArrayND.prototype.setValue = function (value) {
var indices = arguments,
nest = this,
index, i;
// note the range of values since the last recursion is being set to a value
for (i = 1; i < indices.length - 2; i++) {
index = indices[i];
if (nest[index] instanceof ArrayND) {
nest = nest[index];
} else if (typeof nest[index] === "undefined") {
// recursive functionality!
nest = nest[index] = new ArrayND();
} else {
// we don't want to get rid of this value by accident!
return false;
}
}
// now "nest" is equal to the ArrayND you want to set the value inside of
index = indices[i];
nest[index] = value;
// we set the value successfully!
return true;
}
ArrayND.prototype.getValue = function () {
var indices = arguments,
nest = this,
index, i;
// note the range because we're getting the last value
for (i = 0; i < indices.length; i++) {
index = indices[i];
// for last recursion, just has to exist, not be ArrayND
if (nest[index]) {
nest = nest[index];
} else {
// nothing is defined where you're trying to access
return undefined;
}
}
return nest;
}
var arrayND = new ArrayND();
arrayND.setValue(1, 0, 0, 0);
arrayND.setValue("stock", 1, 0, 0);
arrayND.setValue("pending", 5, 1, 0);
// you can treat it like a normal 3D array if you want
console.log(arrayND[0][0][0]); // 1
console.log(arrayND[1][0][0]); // "stock"
console.log(arrayND[5][1][0]); // "pending"
// or use a nicer way to get the values
console.log(arrayND.getValue(1, 0, 0)); // "stock"
// phew, no errors!
console.log(arrayND.getValue(3, 1, 0)); // undefined
// some awesome recursive functionality!
console.log(arrayND.getValue(5).getValue(1).getValue(0)); // "pending"

Check for continuous order in array in javascript

var userInput = prompt('enter number here');
var number = new Array(userInput.toString().split(''));
if (number ????){ //checks if the number is in a continuous stream
alert(correct);
}
else{
alert(invalid);
}
In Javascript, what can I do at "????" to check if it is in a continuous order/stream? Also how can I do this so that it only checks for this order/stream after a specific index in the array? Meaning the user enters say "12345678901234" which would pop up correct, but "12347678901234" would pop up invalid?(note there are two 7's) For the second part "3312345678901234" would pop up correct, how can this be implemented?
You can make a function that checks any string for a stream of continuous/increasing alpha-numeric characters starting at a given index like this:
function checkContinuous(str, startIndex) {
startindex = startIndex || 0;
if (str.length <= startIndex) {
return false;
}
var last = str.charCodeAt(startIndex);
for (var i = startIndex + 1; i < str.length; i++) {
++last;
if (str.charCodeAt(i) !== last) {
return false;
}
}
return true;
}
If it's numbers only and wrapping from 9 back to 0 is considered continuous, then it's a little more complicated like this:
function checkContinuous(str, startIndex) {
// make sure startIndex is set to zero if not passed in
startIndex = startIndex || 0;
// skip chars before startIndex
str = str.substr(startIndex);
// string must be at least 2 chars long and must be all numbers
if (str.length < 2 || !/^\d+$/.test(str)) {
return false;
}
// get first char code in string
var last = str.charCodeAt(0);
// for the rest of the string, compare to last code
for (var i = 1; i < str.length; i++) {
// increment last charCode so we can compare to sequence
if (last === 57) {
// if 9, wrap back to 0
last = 48;
} else {
// else just increment
++last;
}
// if we find one char out of sequence, then it's not continuous so return false
if (str.charCodeAt(i) !== last) {
return false;
}
}
// everything was continuous
return true;
}
Working demo: http://jsfiddle.net/jfriend00/rHH4B/
No need for arrays, just back though the string one character at a time.
When you hit a 0, substitute 10, and continue until the number
is not one more than the previous one.
function continuousFromChar(str, start){
start= start || 0;
var i= 0, L= str.length, prev;
while(L){
c= +(str.charAt(-- L)) || 10; // use 10 for 0
prev=+(str.charAt(L- 1));
if(c-prev !== 1) break;
}
return start>=L;
}
var s= "3312345678901234";
continuousFromChar(s,2)
/* returned value: (Boolean)
true
*/
This will do the checking in real-time entry, but a similar principle could be used to check an entry on a button submit or similar. I was not 100% sure as to which way you wanted it, so I went for the live method.
HTML
<input id="stream" type="text" />
Javascript
window.addEventListener("load", function () {
document.getElementById("stream").addEventListener("keyup", function (evt) {
var target = evt.target;
var value = target.value;
var prev;
var last;
var expect;
target.value = value.replace(/[^\d]/, "");
if (value.length > 1) {
prev = parseInt(value.slice(-2, -1), 10);
last = parseInt(value.slice(-1), 10);
expect = prev + 1;
if (expect > 9) {
expect = 0;
}
if (last !== expect) {
target.value = value.slice(0, value.length - 1);
}
}
}, false);
});
On jsfiddle
By changing the value here
if (value.length > 1) {
You can change where the checking starts.
Update: Ok, so it is function that you want, and you insist that it splits the string into an array. Then using the above as a reference, you could convert it to something like this.
Javascript
window.addEventListener("load", function () {
var testStrings = [
"0123456789012",
"0123456789",
"0123455555",
"555012345678901234",
"0123455555"];
function test(string, offset) {
if (typeof string !== "string" || /[^\d]/.test(string)) {
return false;
}
var array = string.split("");
var prev;
var last;
var expect;
return !array.some(function (digit, index) {
if (index >= offset) {
prev = parseInt(array[index - 1], 10);
last = parseInt(digit, 10);
expect = prev + 1;
if (expect > 9) {
expect = 0;
}
if (last !== expect) {
return true;
}
}
return false;
});
}
testStrings.forEach(function (string) {
console.log(string, test(string, 1));
});
});
On jsfiddle
As your question does not fully specify all possibilities, the above will return true for an empty string (""), of course you can simply add a check at the very beginning for that.
I also do not perform any checking for a valid number for your offset, but again this is something simple that you can add.
Of course these are just one (two) of many possible solutions, but hopefully it will set your mind in the right direction of thought.
There are some good answers here, but I would like to show a slight variation. I think it is important to showcase some different aspects of JavaScript and separating interests in code.
Functions as first class objects are cool - the exact rules for "continuous" can be changed with only changing the predicate function. Perhaps we should allow skipping numbers? No problem. Perhaps we allow hex digits? No problem. Just change the appropriate follows function for the specific rules.
This can be implemented generically because strings support indexing. This will work just as well over other array-like objects with an appropriate follows function. Note that there are no string-specific functions used in the continuous function.
Code also on jsfiddle:
// returns true only iff b "follows" a; this can be changed
function follows_1Through9WithWrappingTo0(b,a) {
if (b === "1" && a === undefined) {
// start of sequence
return true;
} else if (b === "0" && a === "9") {
// wrap
return true;
} else {
// or whatever
return (+b) === (+a) + 1;
}
}
function continuous(seq, accordingTo, from) {
// strings can be treated like arrays; this code really doesn't care
// and could work with arbitrary array-like objects
var i = from || 0;
if ((seq.length - i) < 1) {
return true;
}
var a = undefined;
var b = undefined;
for (; i < seq.length; i++) {
b = seq[i];
if (!accordingTo(b, a)) {
return false; // not continuous
}
a = b;
}
return true;
}
function assert(label, expr, value) {
if (!(expr === value)) {
alert("FAILED: " + label);
}
}
var follows = follows_1Through9WithWrappingTo0;
assert("empty1", continuous("", follows), true);
assert("empty2", continuous("foobar", follows, 6), true);
assert("skip", continuous("331234", follows, 2), true);
assert("good 1", continuous("123456789", follows), true);
assert("good 2", continuous("12345678901234", follows), true);
assert("bad seq 1", continuous("12347678901234", follows), false);
assert("bad seq 2", continuous("10", follows), false);
// here a different predicate ensures all the elements are the same
var areAllSame = function (b, a) {
return a === undefined || a === b;
};
assert("same", continuous("aaaaa", areAllSame), true);
Note that the skipping could also be extracted out of the continuous function: in a language with better "functional" collection support, such as C#, this is exactly what I'd do first.

Categories