I want to exectute a function, preferably inside the forEach, for every element that is surrendered by 2 higher or equal number, or if its first or last element, just compared to second, or second last number.
I come up with this code, but I'm sure there is a better way:
var Pointdata = [98,59,39,0,48,85,19,43,3,98,65,100];
Pointdata.forEach(function(Current,i,array){
if (Current <= array[i+1] && Current <= array[i-1]) {
DrawPoint(Current,i,array);
}
else if (Current <= array[i+1] && i == 0) {
DrawPoint(Current,i,array);
}
else if(Current <= array[i-1] && i+1 == array.length) {
DrawPoint(Current,i,array);
}
function DrawPoint(Current,i,array) {
// marks peak points of canavas chart.
}
You could use just a single condition inside, Current is a.
if ((i + 1 === array.length || a <= array[i + 1]) && (i === 0 || a <= array[i - 1])) {
DrawPoint(a, i, array);
}
What about this?
for (i = 1; i < array.length - 1; i++) {
var Current = array[i];
if (Current <= array[i+1] && Current <= array[i-1]) {
DrawPoint(Current,i,array);
}
}
Couple of benefits:
You can skip edge cases like start and end indices
Only one conditional to think about
But if you want to keep those edge cases you can write them all in one if block separating them by or conditions like if ((Current <= array[i+1] && Current <= array[i-1]) || (Current <= array[i+1] && i == 0) || (Current <= array[i-1] && i+1 == array.length))
function markPeaks(data, draw) {
var xs = [Infinity].concat(data).concat(Infinity)
xs.forEach(function(x, i, array) {
if (Number.isFinite(x)) // skip first and last
if (array[i-1] >= x && x <= array[i+1]) // n-1 ≥ n ≤ n+1
draw(x, i-1, array) // minus1 because of 1st 'helper' Infinity
})
}
markPeaks(/*pointdata, /*drawpoint*/)
Related
Description
I'm trying to implement a JS version of Levenshtein distance function, using the matrix method described on this page in Wikipedia.
Problem
The algorithm works as expected, it returns the difference between the strings (the amount of edits you need to do for strings to be equal), except it ignores index 0, no matter what character is at index 0, it always considers it to be "correct":
levenshteinDistance('cat', 'cave') // 2 (correct)
levenshteinDistance('cat', 'cap') // 1 (correct)
levenshteinDistance('cat', 'hat') // 0 (should be 1)
levenshteinDistance('cat', 'rat') // 0 (should be 1)
levenshteinDistance('cat', 'bat') // 0 (should be 1)
Code
https://codepen.io/aQW5z9fe/pen/mdPvJqV?editors=0011
function levenshteinDistance (string1, string2, options) {
if (string1 === string2) { return 0 }
let matrix = []
let cost
let i
let j
// Init first column of each row
for (i = 0; i <= string1.length; i++) {
matrix[i] = [i]
}
// Init each column in the first row
for (j = 0; j <= string2.length; j++) {
matrix[0][j] = j
}
// Fill in the rest of the matrix
for (i = 1; i <= string1.length; i++) {
for (j = 1; j <= string2.length; j++) {
// Set cost
cost = string1[i] === string2[j]
? 0
: 1
// Set the distances
matrix[i][j] = Math.min(
matrix[i - 1][j] + 1, // deletion
matrix[i][j - 1] + 1, // insertion
matrix[i - 1][j - 1] + cost // substitution
)
if (
options.allowTypos &&
i > 1 &&
j > 1 &&
string1[i] === string2[j - 1] &&
string1[i - 1] === string2[j]
) {
matrix[i][j] = Math.min(
matrix[i][j],
matrix[i - 2][j - 2] + 1
) // transposition
}
}
}
return matrix[string1.length][string2.length]
}
console.log(
levenshteinDistance('cat', 'hat', { allowTypos: true })
)
I think you just made a small mistake I think this:
cost = string1[i] === string2[j]
Should be :
cost = string1[i-1] === string2[j-1]
Since otherwise you never check for the cost of the first letter in the strings and the cost for the letters after that in case of the substitution is always derived from that.
EDIT:
The part inside the transpose section/ allow typo section should also be changed from:
string1[i] === string2[j - 1] &&
string1[i - 1] === string2[j]
to
string1[i-1] === string2[j - 2] &&
string1[i - 2] === string2[j-1]
After looking at the Wikipedia article they for some reason use 1 indexed arrays for the strings and 0 indexed arrays for the matrix, so I guess that was the root of the problem.
I am building an application similar to minesweeper where a user will click a square on a grid and the app will tell the user how many of the surrounding squares contain an 'X'. I have my code working when I only check up, down, left, and right. My code is beginning to get very long since there are quite a few edge cases to account for. I am going to begin checking diagonals for 'X's and I want to come up with a shorter way to check these cases.
Can anyone help me develop a for loop or other short hand way to write this code. Here is what I have so far for a 8x8 grid.
Here is my sandbox: https://codesandbox.io/s/6y6wzo001w
showNumber= () => {
let Xcounter = 0;
console.log(this.props.keys)
console.log(this.props.reduxState.reducer.board[this.props.keys])
if(this.props.keys% 8 ===0){
if(this.props.reduxState.reducer.board[this.props.keys +1] === 'X'){
Xcounter++
}
}
if(this.props.keys% 8 ===7){
if(this.props.reduxState.reducer.board[this.props.keys -1] === 'X'){
Xcounter++
}
}
if(this.props.keys/8 <1){
if(this.props.reduxState.reducer.board[this.props.keys +8] === 'X'){
Xcounter++
}
}
if(this.props.keys/8 >=7){
if(this.props.reduxState.reducer.board[this.props.keys -8] === 'X'){
Xcounter++
}
}
if(this.props.keys % 8 !== 0 && this.props.keys % 8 !== 7){
if(this.props.reduxState.reducer.board[this.props.keys +1] === 'X'){
Xcounter++
}
if(this.props.reduxState.reducer.board[this.props.keys -1]=== 'X'){
Xcounter++
}
}
if(Math.floor(this.props.keys)/8 > 0 && Math.floor(this.props.keys)/ 8 < 7){
if(this.props.reduxState.reducer.board[this.props.keys +8] === 'X'){
Xcounter++
}
if(this.props.reduxState.reducer.board[this.props.keys -8]=== 'X'){
Xcounter++
}
}
if(this.props.id === 'X'){
this.setState({...this.state, clicked: true, counter: 'X'})
return this.state.counter;
}
this.setState({...this.state, clicked: true, counter: Xcounter})
return this.state.counter;
}
Assuming you have an array this.props.reduxState.reducer.boardof length 64 with 'X's or non-'X's, one could simply loop through the x and y directions like so:
let Xcounter = 0;
//save the board for shorter and more readable code
let board = this.props.reduxState.reducer.board;
//the current index we've clicked on
let c = this.props.keys;
//we're going to check if we're at the edge of the board.
//I'll explain these later.
let minX = c%8 == 0 ? 0 : -1;
let maxX = c%8 == 7 ? 0: 1;
let minY = (c-minX)/8 == 0 ? 0 : -1;
let maxY = (c-minY)/8 == 7 ? 0 : 1;
for( let x = minX; x <= maxX; ++x ){
for( let minY = -1; y <= maxY; ++y ){
if( board[c+x+8*y)] == 'X' ){ Xcounter++; }
}
}
//we also checked the square itself, but we didn't want to
if( board[c] == 'X' ){ Xcounter--; }
This assumes the indeces of the board are from right to left, and then top to bottom, not the other way around (i.e. board[7] is the top-right corner, not the bottom-left one).
As far as what this actually does; essentially, we look whether or not we're at the edge of a board, and find the relative x- and y-coordinates we have to check. To visualize:
Here minX=0, because going to the left of the current clicked square c would throw us off the board. maxX=1 though, because we can check to the right of the clicked square. Similarly, we check the y-coordinates.
Assuming that your checks are already correct, let's work with what you already have.
Try to rewrite what you actually have with more condensed style to get an overview as a first step and introduce a board side constant as a second:
showNumber = () => {
const BOARD_SIDE = 8;
let Xcounter = 0;
let keys = this.props.keys;
let board = this.props.reduxState.reducer.board;
console.log(keys);
console.log(board[this.props.keys]);
for (let edge = BOARD_SIDE; edge < BOARD_SIDE * BOARD_SIDE; edge += BOARD_SIDE) {
if (keys % edge === 0 && board[keys + 1] === "X") Xcounter++;
if (keys % edge === (edge - 1) && board[keys - 1] === "X") Xcounter++;
if (keys / edge < 1 && board[keys + edge] === "X") Xcounter++;
if (keys / edge >= (edge - 1) && board[keys - edge] === "X") Xcounter++;
if (keys % edge !== 0 && keys % edge !== (edge - 1)) {
if (board[keys + 1] === "X") Xcounter++;
if (board[keys - 1] === "X") Xcounter++;
}
if (Math.floor(keys) / edge > 0 && Math.floor(keys) / edge < (edge - 1)) {
if (board[keys + edge] === "X") Xcounter++;
if (board[keys - edge] === "X") Xcounter++;
}
}
if (this.props.id === "X") {
this.setState({ ...this.state, clicked: true, counter: "X" });
return this.state.counter;
}
this.setState({ ...this.state, clicked: true, counter: Xcounter });
return this.state.counter;
};
as answer to an exercise in which I had to create a function that given an array of numbers return the number with most occurrences, and if more than one number had the max number of occurrences return the minor one. This is the implementation I made, but I'm pulling my hair figuring out why it return 10 instead of 9 in the example.
It appears to be evaluating 10 < 9 as true. What's wrong?
function maxOccurencies(arr) {
var aux = [], max = 0, final = null;
for (var i=0,t=arr.length; i<t; i++) {
aux[arr[i]] = (aux[arr[i]] || 0) + 1;
if (aux[arr[i]] > max) max = aux[arr[i]];
}
for (x in aux) {
if ( aux[x] == max && (x < final || final == null)) {
final = x;
}
}
return final;
}
document.write(maxOccurencies([10,10,10,9,9,9,8,7,4,5,1]));
Putting typeof(x) in your second loop reveals that some of your variables are being cast as type string! Still looking into exactly where this is occurring. You can replace
if ( aux[x] == max && (x < final || final == null)) {
with
if ( aux[x] == max && (parseInt(x) < parseInt(final) || final == null)) {
to return the correct value of 9.
Edit:
Very interesting, I was unaware of Javascript's exact handling of arrays in for...in loops. See the following other questions for more information:
JavaScript For-each/For-in loop changing element types
Why is using “for…in” with array iteration such a bad idea?
Also note that you can use arr.forEach(function(element){...}); and the elements are returned with their types intact.
I think the problem is just that the x in aux is not a number so the if statement isn't evaluating correctly. when converted to a number then it returns 9 (below).
(3 == 3 && ("10" < "9" || "9" == null)) evaluates to true
function maxOccurencies(arr) {
var aux = [], max = 0, final = null;
for (var i=0,t=arr.length; i<t; i++) {
aux[arr[i]] = (aux[arr[i]] || 0) + 1;
if (aux[arr[i]] > max) max = aux[arr[i]];
}
for (x in aux) {
if ( aux[x] == max && (parseInt(x) < final || final == null)) {
final = parseInt(x);
}
}
return final;
}
document.write(maxOccurencies([10,10,10,9,9,9,8,7,4,5,1]));
"I'm pulling my hair figuring out why it return 10 instead of 9 in the example."
That's because in this sort of comparison, 10 is smaller than 9,8,7,6,5,4,3, 2 but a bit grater than 1.
:)
This small type correction will fix it:
function maxOccurences(arr) {
aux = [], max = 0, final = null;
for (var i=0,t=arr.length; i<t; i++) {
aux[arr[i]] = (aux[arr[i]] || 0) + 1;
if (aux[arr[i]] > max) max = aux[arr[i]];
}
for (x in aux) {
if ( aux[x] == max && (+x < final || final == null)) {
final = x;
}
}
return final;
}
I'm trying to compare the values of a node. Using the flood-fill algorithm I was able to check vertically and horizontally every node of my grid. Now I have to update my code to check the cells that sit on the diagonal, as in the image below:
In red you have the current node, in yellow are the cells that need to be checked.
Here is a snippet of what I have so far:
var mapWidth = Math.sqrt(mapData.length);
var currentCell = $('[data-x="'+ x +'"][data-y="'+ y +'"]');
if (x < 0 || y < 0 || x > mapWidth || y > mapWidth) {
return;
}
if(mapData[x*mapWidth+y] !== 0 || currentCell.hasClass('cell-grey')) {
if(mapData[x*mapWidth+y] > 0) {
currentCell.addClass('cell-grey').css('opacity', '1');
}
if(mapData[(x-1)*mapWidth+(y-1)] > 0 && mapData[(x-1)*mapWidth+(y-1)] < mapWidth) {
currentCell.addClass('cell-grey').css('opacity', '1');
return;
}
if(mapData[(x-1)*mapWidth+(y+1)] > 0 && mapData[(x-1)*mapWidth+(y+1)] < mapWidth) {
currentCell.addClass('cell-grey').css('opacity', '1');
return;
}
if(mapData[(x+1)*mapWidth+(y-1)] > 0 && mapData[(x+1)*mapWidth+(y-1)] < mapWidth) {
currentCell.addClass('cell-grey').css('opacity', '1');
return;
}
if(mapData[(x+1)*mapWidth+(y+1)] > 0 && mapData[(x+1)*mapWidth+(y+1)] < mapWidth) {
currentCell.addClass('cell-grey').css('opacity', '1');
return;
}
return true;
}
mapWidth is the variable that contains all the cells of the grid, and currentCell is the current node cell. This snippet is not really working for me.
When you evaluate mapData[(x-1)*mapWidth+(y-1)], the values of x-1 and y-1 may cause an out-of-bounds reference, which returns undefined. You have to validate the cell coordinates before accessing the array.
You can iterate over the four diagonal neighbors like this:
for (var neighborX = x - 1; neighborX <= x + 1; neighborX += 2) {
if (neighborX < 0 || neighborX >= mapWidth) {
continue;
}
for (var neighborY = y - 1; neighborY <= y + 1; neighborY += 2) {
if (neighborY < 0 || neighborY >= mapWidth) {
continue;
}
currentCell.addClass('cell-grey').css('opacity', '1');
}
}
I'm not sure exactly what you're trying to accomplish, but it looks like there are other bugs in your code. You probably don't want to return immediately after turning a cell gray, for example. If you want each of the diagonal neighbors to turn gray, the loop above should do the trick.
This line near the beginning of your code contains a subtle error:
if (x < 0 || y < 0 || x > mapWidth || y > mapWidth) {
Valid indices range from 0 through mapWidth - 1, so you should write:
if (x < 0 || y < 0 || x >= mapWidth || y >= mapWidth) {
I'm trying to do some simple tests to help further my javascript knowledge (which is quite fresh). Goal 1 is to print numbers from 1-100 that aren't divisible by 5 or 3.
I tried the following:
for (var i = 1; i <= 100; i ++)
{
if (i%3 !== 0 || i%5 !== 0){
console.log(i);
}
}
This logs EVERY number from 1-100, and I can't tell why. Probably the simplest simplest questions here but it's doing my head in!
I think you mean &&, not ||. With ||, you're basically testing to see if the number is not divisible by 3 or by 5 - only if a number is divisible by both do you reject it (in other words, multiples of 15).
The typical answer to FizzBuzz is:
if( i%3 == 0 && i%5 == 0) FizzBuzz
elseif( i % 3 == 0) Fizz
elseif( i % 5 == 0) Buzz
else number
So to get directly to the number you need for i%3==0 to be false AND i%5==0 to be false. Therefore, you want if( i%3 !== 0 && i%5 !== 0)
Here's a quite simple FizzBuzz function that accepts a range of numbers.
function fizzBuzz(from, to) {
for(let i = from; i <= to; i++) {
let msg = ''
if(i % 3 == 0) msg += 'Fizz'
if(i % 5 == 0) msg += 'Buzz'
if(msg.length == 0) msg = i
console.log(msg)
}
}
fizzBuzz(1, 25)
As for a more complex solution, that's one way you could define a higher order function which generates customized FizzBuzz functions (with additional divisors and keywords)
function fizzBuzzFactory(keywords) {
return (from, to) => {
for(let i = from; i <= to; i++) {
let msg = ''
Reflect.ownKeys(keywords).forEach((keyword) => {
let divisor = keywords[keyword]
if(i % divisor == 0) msg += keyword
})
if(msg.length == 0) msg = i
console.log(msg)
}
}
}
// generates a new function
const classicFizzBuzz = fizzBuzzFactory({ Fizz: 3, Buzz: 5 })
// accepts a range of numbers
classicFizzBuzz(1, 25)
const extendedFizzBuzz = fizzBuzzFactory({ Fizz: 3, Buzz: 5, Bazz: 7, Fuzz: 11 })
extendedFizzBuzz(1, 25)
I attacked this the same was as Niet the Dark Absol:
for (var n = 1; n <= 100; n++) {
if (n % 3 == 0 && n % 5 == 0)
console.log("FizzBuzz");
else if (n % 3 == 0)
console.log("Fizz");
else if (n % 5 == 0)
console.log("Buzz");
else
console.log(n);
}
However, you can also do it this way:
for (var n = 1; n <= 100; n++) {
var output = "";
if (n % 3 == 0)
output += "Fizz";
if (n % 5 == 0)
output += "Buzz";
console.log(output || n);
}
One of the hardest parts of learning JavaScript - or any language - for me is understanding solutions can come in many ways. I like the first example more, but it's always good to keep thinking and look at other options.