Checking a 2D Array Bounds in Javascript - javascript

I have a 2-dimensional array that I want to check the bounds in Javascript. I prefer doing this without checking each index independently.
For example if my 2d array is...
dataset[row0-1][column+column0]
I really do not want to have to do the following...
if(row0-1 >0)
{
if(dataset[row0-1].length >= column+column0)
{
data = {label : dataset[row0-1][column+column0]};
}
}
The problem is that I have to first check the row and then check the column. I prefer doing both of these checks with one operation or on one line. Rather then returning an out of bounds error, why doesn't Javascript just return null or undefined?
For example, in a future version of Javascript, wouldn't it be better if we could do this?
if(dataset[row0-1][column+column0] != undefined)
{
data = {label : dataset[row0-1][column+column0]};
}
else
{
...
}

You can write a function to check:
function CheckArrayIndex(x, y) {
if (dataset.length > x && dataset[x].length > y) {
return dataset[x][y];
}
return null;
}
Then you can use it like this:
if(CheckArrayIndex(row0-1,column+column0) != null){
data = {label : dataset[row0-1][column+column0]};
}

I think the reason for checking each index independently is because each dimension can have different lengths on each index.
I know C# has Multidimensional Arrays, but Javascript uses Jagged Arrays.
I do not picture this changing any time soon.

You can easily combine nested if-clauses to a one-liner using the AND-operator &&:
if (row0-1 > 0 && dataset[row0-1].length >= column+column0){
data = {label : dataset[row0-1][column+column0]};
}
although you really should check for the array's length, not (only) greater-than 0. Better:
if (row0-1 > 0 && row0-1 < dataset.length && column+column0 < dataset[row0-1].length)
data = {label: dataset[row0-1][column+column0]};
}

I do mostly like this: say we have 2d array arr and we need to access an element which isn't there.
var arr = [/*elements*/]
var get = function(x, y) {
if(!arr[x]) {
return false;
}
return arr[x][y] || false;
}

Using the #dmck answers, I use prototype in Array object.
Function:
Array.prototype.CheckBounds = function (x, y)
{
if (this[x] === undefined)
return false;
if (this.length > x && this[x].length > y) {
return true;
}
return false;
}
How to use:
if(myArray.CheckBounds(5,10)) //Check bounds
{
//OK
}else{
//Out of bounds
}

Related

Arrays in arrays, length always is 0, json not working

I try to create arrays in arrays and then forward it to JSON.
First problem, when i try to use a lista.length or something, console always return 0. I tried to overpass this problem and create another array, but now I have problem with JSON - always return [] - empty lista array.
var lista = [];
var licz = [];
function ListujBledy(value, where) {
var checked = document.getElementById(value).checked;
var desc;
if (value == "blad-tab") {
desc = "Nieprzeźroczysta lista graczy.";
} else if (value == "blad-tab1") {
desc = "Brak listy graczy na początkowym zrzucie ekranu.";
} else if (value == "blad-tab2") {
desc = "Brak listy graczy na końcowym zrzucie ekranu.";
}
if (checked == true) {
if (lista[where] == undefined) {
var temp = [];
temp[value] = desc;
lista[where] = temp;
licz[where] = 1;
} else if (licz[where] == 1) {
var temp = lista[where];
temp[value] = desc;
lista[where] = temp;
licz[where] = 2;
} else if (licz[where] == 2) {
var temp = lista[where];
temp[value] = desc;
lista[where] = temp;
licz[where] = 3;
}
} else {
if (licz[where] == 1) {
delete lista[where];
licz[where] = 0;
} else if (licz[where] == 2) {
delete lista[where][value];
licz[where] = 1;
} else if (licz[where] == 3) {
delete lista[where][value];
licz[where] = 2;
}
}
console.log(lista.length);
console.log(lista);
console.log(JSON.stringify(lista));
console.log("---------------------------------------------------------");
}
Console log from browser:
I don't have more ideas, I can't use lista[0], lista[1] etc. everything must be functional. Eveyrthing is taken from variables but everywhere I was looking for information about it, everybody using numbers in key or permanent keys.
Editied version of code:
I know that checked could have been better done, so I corrected it here.
https://jsfiddle.net/5vdgLtue/1/
The main problem is that even if I do this https://jsfiddle.net/5vdgLtue/0/ the array returns this element, but the length function says it is 0.
It looks like you might be starting out with javascript. Keep in mind that you haven't actually called the function at any point in your code. Is that the case or are you not sharing the full code you have run?
There is only one condition in which the array 'lista' could gain value: if 'check'== true and 'where' == undefined.
In that scenario, you declare the array 'temp' and declare temp[value]= desc. However, if 'value' contains a value different than "blad-tab", "blad-tab1" or "blad-tab2", 'desc' remains empty therefore temp[value] has a name but no value. You are then assigning a named valueless item to lista[where] which would explain why your console displays content but no length. btw, this would be easier if you named your variable something other than 'value' .
Problem is your selector points to the parent element. In jquery you could do this less code but assuming you're not using jQuery. Try something like:
function getDesc(chkboxName) {
var checkboxes = document.getElementsByName(chkboxName);
//or use getElementsbyClassName...
var checkboxesChecked = [];
// loop over them all
for (var i=0; i<checkboxes.length; i++) {
// And stick the checked ones onto an array...
if (checkboxes[i].checked) {
checkboxesChecked.push(checkboxes[i]);
}
}
for (var i=0; i<checkboxesChecked.length; i++) {
if (checkboxesChecked[i].value === "blad-tab") {
desc = "Nieprzeźroczysta lista graczy.";
} else if (checkboxesChecked[i].value === "blad-tab1") {
desc = "Brak listy graczy na początkowym zrzucie ekranu.";
} else if (checkboxesChecked[i].value === "blad-tab2") {
desc = "Brak listy graczy na końcowym zrzucie ekranu.";
}
}
return desc;
}
This should answer most of your questions.
In summary:
In javascript there are 2 types of arrays: standard arrays and associative arrays
[ ] - standard array - 0 based integer indexes only
{ } - associative array - javascript objects where keys can be any strings
What you are doing is using array in an associative manner. Basically, you are adding properties to your array objects, unlike a standard array where you would only assign values by zero-indexed numbers like temp[0]='something', lista[1]='some other thing' etc.
If you want the length of the key set of the array, then you can use Object.keys(lista).length. This should solve your problem.

How to insert a string in an array with a specific order

So I have the following array :
let array = ['9h00','9h30','9h45','10h00','10h15']
Let's say I want to insert '9h15' between '9h00' && '9h30'
How would one do it in a fast & efficient solution ?
EDIT: I have been unclear, the index of the insert would change depending on the array. It won't always be the following position : array[1].
Thanks in advance!
If every item has the same format (\d?\d)h(\d{2}) then we can do the following :
First we need a function to convert the string to an object or something we can work with, I'll go with an object :
function timeStringToObj(str){
var re = "^(\d?\d)h(\d\d)$";
var h = str.replace(re, "$1");
var m = str.replace(re, "$2");
return {
hours: parseInt(h),
minutes: parseInt(m)
};
}
Then we will need to ensure that the array is sorted, for instance "9h15" < "9h16" therefore "9h15"'s index is < "9h16"'s index , (if not use array.sort(/*some sorting function if necessary*/)) and loop through it to find the spot (I'll use a function of course), I'll consider your array as a global variable :
/**
*#param timeObjA an object that is the return value of a call of timeStringToObj
*#param timeObjB an object that is the return value of a call of timeStringToObj
*/
function AgeB(timeObjA, timeObjB){//A greater than or equal to B
return (timeObjA.hours >= timeObjB.hours && timeObjA.minutes >= timeObjB.minutes);
}
/**
*#param a an object that is the return value of a call of timeStringToObj
*#param b an object that is the return value of a call of timeStringToObj
*/
function AleB(a, b){//A less than or equal to B
return (timeObjA.hours <= timeObjB.hours && timeObjA.minutes <= timeObjB.minutes);
}
function putInTimeArray(str){
var val = timeStringToObj(str);
for(let i = 0 ; i < array.length ; i+=1){
var curr = timeStringToObj(array[i]);
//first check : elem >= last
if( AgeB(val, curr) && i===(array.length-1) ){
array.push(str);
return true;
}
//second check : elem <= first
if( AleB(val, curr) && i===0 ){
array.unshift(str);
return true;
}
//last check : first < elem < last
if(i!=0 && i!=(array.length - 1)){
if(AgeB(val, curr)){
array.splice(i+1,0,str);
return true;
}
if(AleB(val, curr){
array.splice(i-1,0,str);//here i-1 is safe since i!=0 (condition)
return true;
}
}//end of last check
}//end of for-loop
}//end of function
If you're having doubts regarding my usage of splice please refer to this : How to insert an item into an array at a specific index?
EDIT
You'll probably need a more sophisticated regex to be more appropriate be this will do the job just fine if you don't go that crazy with those strings
You can push and sort like:
array.push("9h15").sort().reverse(); // ["9h45", "9h30", "9h15", "9h00", "10h15", "10h00"]

Why is the first argument of reduce() returning undefined?

I'm trying to write a function that takes in an array as an input. If the integer is positive, it counts it. If the integer is negative, it sums it.
I figured that that the reduce() helper in js would be the best way to go about this, but I keep returning undefined for my first argument when it runs.
Here's my code:
function countPositivesSumNegatives(input) {
let countPositive = 0;
let sumNegative = 0
if (input === null || input === []){
return [];
} else {
return input.reduce(function(prev,num){
if (num > 0) {
countPositive++;
}else{
sumNegative = prev + num};
}, 0);
}
return [countPositive, sumNegative];
}
It throws me a TypeError that says:
TypeError: Cannot read property '0' of undefined
When I log 'prev' to the console inside of the reduce function, it logs undefined for all inputs except the first one. The first one, as expected, is 0. But for each following input it logs undefined. Why is this happening?
Thanks in advance.
The callback you pass to .reduce() needs to return the cumulative value (the value that will be passed as prev to the next iteration of the loop. Since you are returning nothing, you get undefined for the next iteration of your loop.
This complicates what you're trying to do because you are trying to keep track of two values in your loop. As such, you would either have to avoid using prev at all or you'd have to make it be a data structure that had both your values in it. Your use is not a textbook example for .reduce(). Your code is probably simpler with an iteration using .forEach() or for/of.
function countPositivesSumNegatives(input) {
let countPositive = 0;
let sumNegative = 0
if (!input || input.length === 0){
return [];
} else {
input.forEach(function(num){
if (num > 0) {
++countPositive;
} else {
sumNegative += num;
});
}
return [countPositive, sumNegative];
}
Well sorry but this is not a good implementation of this function. But we can correct your function as follows;
function countPositivesSumNegatives(input) {
let countPositive = 0;
let sumNegative = 0;
if (input === null || input === []){
return [];
} else {
sumNegative = input.reduce(function(prev,num){
if (num > 0) {
countPositive++;
} else {
prev += num;
}
return prev; // <---- THE MISSING PART
}, 0);
}
return [countPositive, sumNegative];
}
var data = [1,2,3,4,5,-4,7,-3];
console.log(countPositivesSumNegatives(data));
However while the code works just fine it still involves many issues. When getting into functors like .reduce() you should be able to keep everthing contained within itself and should not refer to variables at the outer scope. Accordingly one can simply rephrase this code as follows;
var data = [1,2,3,4,5,-4,7,-3],
cpsn = a => a.reduce((p,c) => c > 0 ? (p[0]++,p) : (p[1]+=c,p) ,[0,0]);
console.log(cpsn(data))

Javascript Filter Refactor

I am filtering an array of objects using a function that looks like this
var val = 'some text value'
this.someList = this.someList.filter(containsQuery);
function containsQuery(listItem) {
return listItem.Key_One.toLowerCase().indexOf(val) > -1 ||
listItem.Key_Two.toLowerCase().indexOf(val) > -1 ||
listItem.Key_Three.toLowerCase().indexOf(val) > -1
}
My question is what is a better way of filtering on each of the list item key values without having to write a new line for each one? i.e so I can avoid going
listItem.Key_Four.toLowerCase().indexOf(val) > -1
listItem.Key_Five.toLowerCase().indexOf(val) > -1
etc..
Any advice would be great.
Thanks!
You could use get keys of the object with Object.keys and iterate with Array#some.
function containsQuery(listItem) {
return Object.keys(listItem).some(function (k) {
return listItem[k].toLowerCase().indexOf(val) > -1;
});
}
Just a suggestion, array containing all the keys and loop them?
Like
var keys = ['key_one', 'key_two', 'key_three', 'key_four'];
for (i=0; i<keys.length; i++){
if (listItem[keys[i]].toLowerCase().indexOf(val) > -1) return true;
}
return false;
Ah damn, same idea as above, just took too long writing :D

Explode a string into a hashmap for searching?

I have a string like this being returned from my backend:
"1,2,3,4,5,6"
I have a large array locally and want to display only those items not in this list, so I was thinking of exploding this string into an array but how can I search efficiently? As far as I know there are no hashmaps in JS so how does one do this? I just need to check for key existence.
All Javascript objects are also hash tables that can store string or numeric keys:
var x = {};
x["foo"] = 1;
if("foo" in x) { alert("hello!"); }
if("bar" in x) { alert("should never see this"); }
"1,2,3,4,5,6".split(",").some(function(letter) {
return letter === '2'
});
Warning: Might not work in IE (or other crappy browser)
Cross browser version (that relies on native code for performance):
var arr = "1,2,3,4,5,6".split(",");
if(arr.some)
{
arr.some(function(letter) {
return letter === '2'
});
}
else
{
for(var i = 0 ; i < arr.length ; i++ )
{
if(arr[i] === '2') return true;
}
}

Categories