Related
Let's say we want to count the NaN's in a javascript array. We can use
let arr = [...Array(100)].map( (a,i) => i %10==0 ? NaN : i )
console.log(arr)
> [NaN, 1, 2, 3, 4, 5, 6, 7, 8, 9, NaN, 11, 12, 13, 14, 15, 16, 17, 18, 19, NaN, 21, 22, 23, 24, 25, 26, 27, 28, 29, NaN, 31, 32, 33, 34, 35, 36, 37, 38, 39, NaN, 41, 42, 43, 44, 45, 46, 47, 48, 49, NaN, 51, 52, 53, 54, 55, 56, 57, 58, 59, NaN, 61, 62, 63, 64, 65, 66, 67, 68, 69, NaN, 71, 72, 73, 74, 75, 76, 77, 78, 79, NaN, 81, 82, 83, 84, 85, 86, 87, 88, 89, NaN, 91, 92, 93, 94, 95, 96, 97, 98, 99]
let nans = arr.map( aa => isNaN(aa) ? 1 : 0).reduce((acc,a) => acc+a)
console.log(nans)
> 10
That does work.. but it is a bit challenging to remember the reduce() machinery every time. Is there a more concise construct by applying a predicate as so:
arr.count( a => isNan(a))
You can have just a single .reduce where the accumulator is the number of NaNs found so far:
const arr = [...Array(100)].map( (a,i) => i %10==0 ? NaN : i );
const nans = arr.reduce((a, item) => a + isNaN(item), 0);
console.log(nans);
You can filter out the elements that are not NaN.
arr.filter(isNaN).length
//or
arr.filter(function(it){ return isNaN(it); }).length
With forEach loop instead of map and reduce
const nanCount = (arr, count = 0) => (
arr.forEach((num) => (count += isNaN(num))), count
);
const arr = [NaN, 0, 1, 3 , NaN];
console.log(nanCount(arr));
Or while for even bigger...
const arr = [...Array(1e6)].map((a, i) => i % 10 == 0 ? NaN : i);
let
i = arr.length,
nans = 0;
while (i--) {
nans += isNaN(arr[i]);
}
console.log(nans.toExponential());
const arr = [...Array(100)].map((a, i) => i % 10 == 0 ? NaN : i);
const count = (arr, predicate) => {
let c = 0, i = arr.length;
while (i--) c += predicate(arr[i]);
return c
};
const
nans = count(arr, x => isNaN(x)),
sevens = count(arr, x => x % 7 === 0);
console.log(`nans: ${nans}, sevens: ${sevens}`);
UPDATE:
I'm saving multidimensional arrays of the form:
var a = ["t1","a",["t2","a","b",["t3","a","b"],["t4","a","b","c",["t5","a","b"]],],["t6","a","b",["t7","a","b"]]];
in a file calling a standard save file function using JSON.stringify(a) -without the "var a = " and the ";" and later I open the file to a variable like this:
<a id="nof"><label for="fid">Open Data</label></a>
<input id="fid" type="file" style="position: fixed; top: -100em" onchange="ReadFile(this)">
function ReadFile(input) {
var output;
if (input.files.length === 0) {
output = 'No file selected';
window.setTimeout(ReadFile, 1000);
return;
}
var fr = new FileReader();
fr.onload = function() {
var data = fr.result;
var array = new Int8Array(data);
output = JSON.stringify(array, null, ' ');
console.log(array); // output //<------
};
fr.readAsArrayBuffer(input.files[0]);
I tried to adapt the code from this post: Using FileReader.readAsArrayBuffer() on changed files in Firefox ) but I can't assign the data on a variable as a JS array. What I'm getting in console from "array" variable is:
Int8Array(117) [91, 34, 116, 49, 32, 118, 49, 57, 49, 49, 49, 53, 49, 56, 51, 51, 51, 34, 44, 34, 97, 34, 44, 91, 34, 116, 50, 34, 44, 34, 97, 34, 44, 34, 98, 34, 44, 91, 34, 116, 51, 34, 44, 34, 97, 34, 44, 34, 98, 34, 93, 44, 91, 34, 116, 52, 34, 44, 34, 97, 34, 44, 34, 98, 34, 44, 34, 99, 34, 44, 91, 34, 116, 53, 34, 44, 34, 97, 34, 44, 34, 98, 34, 93, 93, 93, 44, 91, 34, 116, 54, 34, 44, 34, 97, 34, 44, 34, 98, 34, …]
Obviously because the data are converted to int8.
From "output" variable I'm getting:
{"0": 91,"1": 34,"2": 116,"3": 49,"4": 32,"5": 118,"6": 49,"7": 57,"8": 49,"9": 49,"10": 49,"11": 53,"12": 49,"13": 56,"14": 49,"15": 51,"16": 52,"17": 48,"18": 34,"19": 44,"20": 34,"21": 97,"22": 34,"23": 44,"24": 91,"25": 34,"26": 116,"27": 50,"28": 34,"29": 44,"30": 34,"31": 97,"32": 34,"33": 44,"34": 34,"35": 98,"36": 34,"37": 44,"38": 91,"39": 34,"40": 116,"41": 51,"42": 34,"43": 44,"44": 34,"45": 97,"46": 34,"47": 44,"48": 34,"49": 98,"50": 34,"51": 93,"52": 44,"53": 91,"54": 34,"55": 116,"56": 52,"57": 34,"58": 44,"59": 34,"60": 97,"61": 34,"62": 44,"63": 34,"64": 98,"65": 34,"66": 44,"67": 34,"68": 99,"69": 34,"70": 44,"71": 91,"72": 34,"73": 116,"74": 53,"75": 34,"76": 44,"77": 34,"78": 97,"79": 34,"80": 44,"81": 34,"82": 98,"83": 34,"84": 93,"85": 93,"86": 93,"87": 44,"88": 91,"89": 34,"90": 116,"91": 54,"92": 34,"93": 44,"94": 34,"95": 97,"96": 34,"97": 44,"98": 34,"99": 98,"100": 34,"101": 44,"102": 91,"103": 34,"104": 116,"105": 55,"106": 34,"107": 44,"108": 34,"109": 97,"110": 34,"111": 44,"112": 34,"113": 98,"114": 34,"115": 93,"116": 93,"117": 93}
So, what is necessary to assign the file data as a JS array variable?
***I don't want to use a more complex format than the above example array (on the top of the page) that uses more characters, for efficiency reasons.
Codes below displayed in html div.
If you want to store in array, replace it.
Try this:
function readFile(file) {
return new Promise((resolve, reject) => {
let fr = new FileReader();
fr.onload = x=> resolve(fr.result);
fr.readAsText(file);
})}
async function read(input) {
msg.innerText= await readFile(input.files[0]);
}
<input type="file" onchange="read(this)"/>
<h3>Content:</h3><pre id="msg"></pre>
I'm trying to create a bot that interprets an array (exp table) and returns the exp difference between two levels.
I'm new to JavaScript still, so I'm sure it's something within my code, I have tried various combinations of array.find, array[x] and moving formula into variables. I just cannot seem to figure it out.
var xparray = [1, 0, 2, 300, 3, 900, 4, 2000, 5, 3700, 6, 6000, 7, 10200, 8, 16200, 9, 23550, 10, 33480, 11, 45280, 12, 60880, 13, 80480, 14, 104180, 15, 130580, 16, 161080, 17, 196480, 18, 236980, 19, 282680, 20, 333680, 21, 390280, 22, 454180, 23, 525580, 24, 604680, 25, 691780, 26, 786980, 27, 896780, 28, 1021580, 29, 1161780, 30, 1317680, 31, 1480180, 32, 1656080, 33, 1845680, 34, 2049180, 35, 2267080, 36, 2499400, 37, 2749300, 38, 3017100, 39, 3303300, 40, 3608200, 41, 3932200, 42, 4272400, 43, 4629200, 44, 5002900, 45, 5393700, 46, 5801900, 47, 6239500, 48, 6707000, 49, 7205000, 50, 7734000, 51, 8598000, 52, 9656400, 53, 10923600, 54, 12478800, 55, 14350800, 56, 16568400, 57, 19160400, 58, 22155600, 59, 25582800, 60, 29470800, 61, 33940800, 62, 38813800, 63, 44129800, 64, 49938800, 65, 56302800, 66, 63297800, 67, 71019800, 68, 79594800, 69, 89187800, 70, 100013800, 71, 112462800, 72, 126343800, 73, 141899800, 74, 159398400, 75, 179148400, 76, 201478400, 77, 226818400, 78, 255468400, 79, 288218400, 80, 325868400];
var tn = (String(message).length);
// !xp 40 60
var a = (String(message).length)-3;
var b = (String(message).length)-3;
var c = (String(message).length)-5;
var d = (String(message).length)-2;
var t0 = message.substring(b, a); //(-3,-3)
var t1 = message.substring(c, b); //(-5,-3)
var t2 = message.substring(d, tn); //(-2,0)
var na = function(t0){return (t0*2)-1};
var nb = function(t1){return (t1*2)-1};
var nc = function(t2){return (t2*2)-1};
var T1 = xparray.find(function(element) {
return element > t2});
var T2 = xparray.find(function(element) {
return element > t0;
});
var T3 = xparray.find(function(element) {
return element > t1;
});
var t3 = function(T1, T2, T3) {
if (message.length = 7) {
return T1 - T2;
} else {
return T1 - T3;
}
};`
I expect this to pull values 40 and 60 from the end of the string '!xp 40 60', interpret the array and pull the next value after 40 (3608200) and the value after 60 (29470800), then preform a calculation to take the 40 value away from the 60 value (29470800-3608200). So far I think the issue lies around the T1, T2 and T3 values as they are always returning 1, or the value in the array after 1 (300).
With one dimensional array:
You can just get the index of the lvl in the array with indexOf and then take the next value (which is the xp needed for that lvl). After that subtract the two and you are good to go:
var xparray = [1, 0, 2, 300, 3, 900, 4, 2000, 5, 3700, 6, 6000, 7, 10200, 8, 16200, 9, 23550, 10, 33480, 11, 45280, 12, 60880, 13, 80480, 14, 104180, 15, 130580, 16, 161080, 17, 196480, 18, 236980, 19, 282680, 20, 333680, 21, 390280, 22, 454180, 23, 525580, 24, 604680, 25, 691780, 26, 786980, 27, 896780, 28, 1021580, 29, 1161780, 30, 1317680, 31, 1480180, 32, 1656080, 33, 1845680, 34, 2049180, 35, 2267080, 36, 2499400, 37, 2749300, 38, 3017100, 39, 3303300, 40, 3608200, 41, 3932200, 42, 4272400, 43, 4629200, 44, 5002900, 45, 5393700, 46, 5801900, 47, 6239500, 48, 6707000, 49, 7205000, 50, 7734000, 51, 8598000, 52, 9656400, 53, 10923600, 54, 12478800, 55, 14350800, 56, 16568400, 57, 19160400, 58, 22155600, 59, 25582800, 60, 29470800, 61, 33940800, 62, 38813800, 63, 44129800, 64, 49938800, 65, 56302800, 66, 63297800, 67, 71019800, 68, 79594800, 69, 89187800, 70, 100013800, 71, 112462800, 72, 126343800, 73, 141899800, 74, 159398400, 75, 179148400, 76, 201478400, 77, 226818400, 78, 255468400, 79, 288218400, 80, 325868400];
var message = '!xp 40 60';
var lvls = [parseInt(message.split(' ')[1]), parseInt(message.split(' ')[2])]; // Getting the lvls in question
lvls = lvls.map(l => xparray[xparray.indexOf(l)+1]); // Getting the xp values in question
console.log(lvls[1] - lvls[0]); // Substract xp values
With two-dimensional array (with use of a map to simplify):
Map that two dimensional array to a Map or use a Map in the first place. Then just get the correct xp value by the lvl key.
var xparray = [[1, 0], [2, 300], [3, 900], [4, 2000], [5, 3700]];
var xpMap = new Map(xparray); // Map constructor takes the two dimensional array (key=lvl, value=xp)
var message = '!xp 2 3';
var lvls = [parseInt(message.split(' ')[1]), parseInt(message.split(' ')[2])]; // Getting the lvls in question
lvls = lvls.map(l => xpMap.get(l)); // Just map it by getting the value for the key
console.log(lvls[1] - lvls[0]); // Substract xp values
I cant figure out a condition that could check for all 6 numbers. I tried using || but its just messy and i know thats not correct.
Using the following Array, create variable called numThrees with the value [13, 23, 33, 43, 53, 63, 73]
var numArray = [13, 15, 17, 23, 25, 27, 33, 35, 37, 43, 45, 47, 53, 55, 57, 63, 65, 67, 73, 75, 77];
var numThrees = [];
for (i = 0; i < numArray.length; i++) {
if (numArray[i] === 13) {
numThrees[i] = numArray[i];
};
};
document.getElementById('q7').innerHTML = numThrees;
you can just check if the remainder of the number with 10 is 3 ,which is for your condition(13,23,33,43,53,63 and 73)
var numArray = [13, 15, 17, 23, 25, 27, 33, 35, 37, 43, 45, 47, 53, 55, 57, 63, 65, 67, 73, 75, 77];
var numThrees = [];
for (i = 0; i < numArray.length; i++) {
if (numArray[i]%10==3) {
numThrees.push(numArray[i]);
};
};
document.getElementById('q7').innerHTML = numThrees;
<div id="q7">
</div>
Hope it helps
There are several ways to do this. Here are two that use different logic to extract the right numbers:
You can do this the manual way:
var numArray = [13, 15, 17, 23, 25, 27, 33, 35, 37, 43, 45, 47, 53, 55, 57, 63, 65, 67, 73, 75, 77];
var numThrees = [];
for(var i = 0; i < numArray.length; ++i){
// Turn the current array element into a string
var strVal = numArray[i].toString();
// If that string ends with "3" add it to the new array:
strVal[strVal.length-1] === "3" ? numThrees.push(numArray[i]) : "";
}
console.log(numThrees);
You can use the Array.prototype.filter method:
var numArray = [13, 15, 17, 23, 25, 27, 33, 35, 37, 43, 45, 47, 53, 55, 57, 63, 65, 67, 73, 75, 77];
// The Array.prototype.filter method iterates every item in
// a given array and allows you to implement any logic you
// like and return any value from the original array you like
// into a new array that will be a filter of the first one.
var numThrees = numArray.filter(function(element){
// Check the current element being iterated for one of
// a designated set of values and return that element
// into the filtered array if it is a match.
switch(element){
case 13:
case 23:
case 33:
case 43:
case 53:
case 63:
case 73:
return element;
default:
break;
}
});
console.log(numThrees);
Your instructions are a bit arbitrary, but here's a more efficient way of doing it:
var numArray = [13, 15, 17, 23, 25, 27, 33, 35, 37, 43, 45, 47, 53, 55, 57, 63, 65, 67, 73, 75, 77];
var numThrees = [];
for (i = 0; i < numArray.length; i+=3) {
numThrees.push(numArray[i]);
};
document.getElementById('q7').innerHTML = numThrees;
Since we can observe that the given array has the desired values at certain indices which are equally spaced apart, there's no need to iterate through the entire array.
Your directions don't specify if we can do it based on the assumption that we know what's in the original array and what index. If this is the case, then you do need to iterate through the array in some fashion, and then test to see if each index contains your desired value.
I'm assuming this is an acceptable solution.
Edit: Based on my understanding (and likely what's more efficient.) I don't think that, in this case, we should be iterating through the entire array when its hard coded. We know what values are in the array, and at what position. It just so happens that the numbers you want are evenly spaced in the numArray, which is even more reason to not test each value to some condition.
Hope this makes sense.
Do you need items ending in 3, or every third item in the array??
Using Array.filter is the most efficent way to achieve either by:
returning values with a remainder of 3 when divisible by 10.
var numArray = [13, 15, 17, 23, 25, 27, 33, 35, 37, 43, 45, 47, 53, 55, 57, 63, 65, 67, 73, 75, 77];
var numThrees = numArray.filter(function(val){
return val % 10 === 3;
});
console.log(numThrees);
If however, you need get every third element in the array you can do the following which returns the item if the iterator has no remainder when divided by 3
var numArray = [13, 15, 17, 23, 25, 27, 33, 35, 37, 43, 45, 47, 53, 55, 57, 63, 65, 67, 73, 75, 77];
var numThrees = numArray.filter(function(val, i) {
return i % 3 === 0;
});
console.log(numThrees);
Convert the array to list and use Contains
var list = numArray.ToList();
if (list.Contains(thing))
...
I'm trying to use a for loop in an array, to make it display the random numbers in sort order (High to lower) when a button is clicked on within the html plus time the action, I have done this and it works by displaying the results with each number on a new line from 100 to 1 and giving the time in milliseconds.
What I'm trying to do, is make it display 10 numbers per line, but not sure how to go about it.
Javascript
function Numberordermatch() {
var start = new Date().getTime();
for (i = 0; i < 1000; ++i) {
var points = [77, 57, 18, 35, 36, 33, 43, 87, 100, 14, 73, 97, 96, 27, 34, 39, 23, 71, 1, 86, 56, 21, 26, 65, 20, 29, 55, 49, 16, 42, 90, 91, 59, 84, 38, 75, 82, 66, 17, 62, 30, 63, 74, 89, 22, 50, 68, 31, 78, 81, 44, 93, 9, 40, 41, 48, 19, 32, 46, 28, 53, 70, 52, 60, 80, 47, 15, 069, 7, 67, 13, 61, 5, 94, 6, 98, 99, 83, 76, 88, 25, 72, 79, 37, 51, 64, 8, 2, 92, 12, 54, 045, 3, 58, 11, 95, 24, 10, 85, 4];
points.sort(function(a, b){return b-a});
document.getElementById("demo").innerHTML = points;
}
var end = new Date().getTime();
var time = end - start;
text = "";
var i;
for (i = 0; i < points.length; i++) {
text += points[i] + "<br>";
}
document.getElementById("demo").innerHTML = text;
document.getElementById("results").innerHTML =
('<strong>This function took: ' + time + 'ms to load</strong>');
}
Based on Ian Brindley answer it could be :
var text = '';
var points = [77, 57, 18, 35, 36, 33, 43, 87, 100, ...]
points.sort(function(a, b){return b-a});
for (i = 0; i < points.length; ++i) {
text += points[i] + ", " + ((i % 10 === 0) ? '<br />' : '');
}
document.getElementById("demo").innerHTML = text;