let's say I have an arbitrary number sequence
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
I need to replace all zeroes with interpolation given from non-zeroes neighbours, so the output would be
let output = [
12, 12, 12, 12, 12,
12, 64, 9, 6,
10.75, 15.5, 20.25,
25, 79, 57, 13, 39,
28.3333, 17.6666,
7, 7,
14, 21, 28, 35, 42,
49,
49
];
While firs zeroes [0, 4] doesn't have left neighbour all their values have to be 12, while last zero has only right resident 49, it would be just 49.
For me, it doesn't really a problem to fill parts where both left and right neighbours are presented, however I'm looking for an universal and elegant solution for this task.
const interpolateValues = (array, index0, index1, left, right) => {
let n = index1 - index0 + 1;
let step = (right - left) / (n + 1);
for(let i = 0; i < n; i++){
array[index0 + i] = left + step * (i + 1);
}
}
const findZerosSequences = (array) => {
var counter = 0;
var index = 0;
var result = [];
for (let i = 0; i < array.length; i++) {
if (array[i] === 0) {
index = i;
counter++;
} else {
if (counter !== 0) {
result.push([index - counter + 1, index]);
counter = 0;
}
}
}
if (counter !== 0) { result.push([index - counter + 1, index]); }
return result;
}
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
//[[0,4], [9, 11], [17, 18], [21, 25], [27, 27]]
let zeroes = findZerosSequences(sequence);
for(let i = 0; i < zeroes.length; i++){
let lf = sequence[zeroes[i][0] - 1];
let rf = sequence[zeroes[i][1] + 1];
if(lf !== undefined && rf !== undefined && lf > 0 && rf > 0){
interpolateValues(sequence, zeroes[i][0], zeroes[i][1], lf, rf);
}
}
console.log(sequence);
let output = [
12, 12, 12, 12, 12,
12, 64, 9, 6,
10.75, 15.5, 20.25,
25, 79, 57, 13, 39,
28.3333, 17.6666,
7, 7,
14, 21, 28, 35, 42,
49,
49
];
You almost got it, let the interpolateValues worry about those edge cases which are easily resolved.
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
const interpolateValues = (array, index0, index1, left, right) => {
if (left === null) left = right;
if (right === null) right = left;
if (left === null && right === null) left = right = 0;
let n = index1 - index0 + 1;
let step = (right - left) / (n + 1);
for (let i = 0; i < n; i++) {
array[index0 + i] = left + step * (i + 1);
}
}
const findZerosSequences = (array) => {
var counter = 0;
var index = 0;
var result = [];
for (let i = 0; i < array.length; i++) {
if (array[i] === 0) {
index = i;
counter++;
} else {
if (counter !== 0) {
result.push([index - counter + 1, index]);
counter = 0;
}
}
}
if (counter !== 0) {
result.push([index - counter + 1, index]);
}
return result;
}
let zeroes = findZerosSequences(sequence);
for (let i = 0; i < zeroes.length; i++) {
let lf = zeroes[i][0] - 1 >= 0 ? sequence[zeroes[i][0] - 1] : null;
let rf = zeroes[i][1] + 1 < sequence.length ? sequence[zeroes[i][1] + 1] : null;
interpolateValues(sequence, zeroes[i][0], zeroes[i][1], lf, rf);
}
console.log(sequence);
If anyone would be interested in spaghetti instead of a valid answer :)
const sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
]
const output = sequence.join(',')
.replace(/^([0,]+)(\d+)/, (_, zeros, number) => {
const n = zeros.match(/0/g).length
return (number + ',').repeat(n) + number
})
.replace(/([^0,]+),([0,]+)([^0,]+)/g, (_, number1, zeros, number2) => {
const n = zeros.match(/0/g).length
const diff = +number2 - +number1
const step = diff / (n + 1)
return number1 + ',' + [...Array(n).keys()].map(i => {
const val = +number1 + (i + 1) * step
return Math.floor(val * 10000) / 10000
}) + ',' + number2
})
.replace(/(\d+)([,0]+)$/, (_, number, zeros) => {
const n = zeros.match(/0/g).length
return number + (',' + number).repeat(n)
}).split(',').map(Number);
console.log(output)
I would keep track of the start and end values when looping over looking for non zeros. When it is the start the starting index will not be set so you know it needs to be the first value. You can loop one extra index and you know it will be the end. For the others it will be the step like you did.
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
let startIndex = -1;
for (var i = 0; i <= sequence.length; i++) {
if (sequence[i] !== 0) {
if (i - startIndex > 1) {
let func;
const startVal = sequence[startIndex];
const endVal = sequence[i];
if (startIndex === -1) {
func = () => endVal;
} else if (i === sequence.length) {
func = () => startVal;
} else {
func = (j) => {
return startVal + (endVal - startVal) / (i - startIndex) * j;
}
}
for (let j = 1; j < i - startIndex; j++) {
sequence[j + startIndex] = func(j);
}
}
startIndex = i;
}
}
console.log(sequence);
Other way is set the start and end and do the calculation
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
let startIndex = -1;
for (var i = 0; i <= sequence.length; i++) {
if (sequence[i] !== 0) {
if (i - startIndex > 1) {
const startVal = startIndex === -1 ? sequence[i] : sequence[startIndex];
const endVal = i === sequence.length ? startVal : sequence[i];
const func = (j) => {
return startVal + (endVal - startVal) / (i - startIndex) * j;
}
for (let j = 1; j < i - startIndex; j++) {
sequence[j + startIndex] = func(j);
}
}
startIndex = i;
}
}
console.log(sequence);
Haven't checked my sample, but you should see the way I guess..
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
let temporaryZerosArray = [];
for (const [id, value] of sequence.entries()) {
if (value) {
if (!temporaryZerosArray.length) continue;
temporaryZerosArray.splice(0, temporaryZerosArray.length - 2);
let [one, two] = temporaryZerosArray;
let lf = sequence[one-1]
let rf = sequence[two+1]
if (
(!!lf && lf > 0) &&
(!!rf && rf > 0)
) interpolateValues(sequence, one,two, lf , rf );
temporaryZerosArray = [];
continue
}
temporaryZerosArray.push(id);
}
Here's a solution that accepts your input array and returns the interpolated output array. I put comments inline with the code to explain how it works. This solution also behaves correctly for arrays of all zeros.
function interpolateArray(input) {
let output = []; // New array for output
let zeros = 0; // Count of sequential zeros
let start = 0; // Starting number for interpolation
for (let i = 0; i < input.length; i++) { // Loop through all input values
let value = input[i]; // Current input value
if (value === 0) zeros++; // If value is zero, increment the zero count
else { // If the value is non-zero...
if (start === 0) start = value; // If the starting value is zero, set start to current non-zero value
if (zeros) { // If there are zeros accumulated...
let step = (value - start) / (zeros + 1); // Compute the step value (current value, minus start, divided by total steps)
for (let j = 1; j <= zeros; j++) output.push(start + (j * step)); // For each zero, push the stepped value to output
zeros = 0; // Reset zero count
}
start = value; // Store the current value as the new start
output.push(start); // Push the current non-zero value to output
}
}
for (let j = 0; j < zeros; j++) output.push(start); // If there are accumulated zeros, that means they were trailing. Push last non-zero value to output for each
return output; // Return the output
}
Update:
Just for fun, I tightened up the code a bit so the function is more compact. It works exactly the same.
function interpolateArray(input) {
let output = [], zeros = 0, start = 0;
input.forEach(value => {
if (value) {
start = start || value;
if (zeros) {
let step = (value - start) / (zeros + 1);
while (zeros--) output.push(start += step);
zeros = 0;
}
output.push(start = value);
} else zeros++;
});
while (zeros--) output.push(start);
return output;
}
Related
After debugging for more than an hour, I found the problem in my code. I do not understand why it updates board[y][x] but not board itself.
Here is the code:
puzzle = [
[0, 0, 7, 0, 0, 6, 2, 0, 0],
[1, 0, 0, 8, 9, 0, 7, 6, 0],
[8, 0, 2, 0, 7, 3, 0, 5, 0],
[0, 0, 0, 1, 0, 9, 5, 0, 6],
[0, 1, 0, 0, 0, 0, 0, 8, 0],
[7, 0, 3, 6, 0, 8, 0, 0, 0],
[0, 7, 0, 2, 4, 0, 6, 0, 3],
[0, 4, 1, 0, 6, 7, 0, 0, 5],
[0, 0, 9, 3, 0, 0, 1, 0, 0]
];
function find_empty(board) {
for (let y = 0; y < 9; ++y) {
for (let x = 0; x < 9; ++x) {
if (board[y][x] === 0) {
return [y, x];
}
}
}
return null;
}
function is_valid(board, num, pos) {
let y = pos[0];
let x = pos[1];
// Horizontal checking...
for (let i = 0; i < 9; ++i) {
if (board[y][i] === num && x !== i) {
return false;
}
}
// Vertical checking
for (let i = 0; i < 9; ++i) {
if (board[i][x] === num && y !== i) {
return false;
}
}
// 3*3 box checking
box_start_y = (Math.floor(y / 3)) * 3;
box_start_x = (Math.floor(x / 3)) * 3;
for (let i = box_start_y; i < box_start_y + 3; ++i) {
for (let j = box_start_x; j < box_start_x + 3; ++j) {
if (board[i][j] === num && y !== i && x !== j) {
return false;
}
}
}
return true;
}
function solve_board(board) {
console.log("start", board);
empty_pos = find_empty(board);
console.log("empty_pos", empty_pos)
if (empty_pos === null) {
return board;
}
let y = empty_pos[0];
let x = empty_pos[1];
for (let num = 1; num < 10; ++num) {
console.log(board)
if (is_valid(board, num, empty_pos)) {
console.log(true, num)
console.log("Before assignment", board[y][x]);
board[y][x] = num;
console.log("y", y, ", x", x);
console.log("After true", board[y][x])
console.log("After true", board);
let solved_board = solve_board(board)
console.log("solved", solved_board);
if (solved_board !== false) {
return solved_board;
}
console.log(num, "did not work!!")
board[y][x] = 0;
}
console.log(false, num)
}
return false;
}
console.log("result", solve_board(puzzle))
The problem is on line 72 in solve_board function.
It updates board[y][x] as seen in the console.logs, but does not affect board. Is it some reference issue or pass by value problem?
If anyone can help me solve this issue, I would be really grateful.
you are assigning the new value correctly. Arrays are passed to the function by reference, so there should be no problem. You can verify it with this code snippet:
const arr = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
function foo(x) {
x[0][0] = 2
}
foo(arr)
console.log(arr[0][0]) // 2
There probably is some issue with the game logic itself, the conditions in the is_valid don't look right. Consider taking a look on this article explaining how to solve sudoku programmatically with logic and without brute force.
Alternatively, I suggest you look at the backtracking algorithm, which tries all possible options, which should be straightforward to implement.
I have the following array:
let arr = [ 1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12, 13, 14, 15,
16, 17, 18, 19, 20,
21, 22, 23, 24, 25 ]
How will I write a function, which will loop through the elements adjacent to it. For example, if I input 13, it will go through 7,8,9,12,14,17,18 and 19 and then the elements adjacent to them i.e. 1,2,3,4,5,6,10,11,15,16,20,21,22,23 and 25.
I have tried looping separately. that is +5,-5,+6,-6,+4,-4,+1 and -1. Unfortunately, I haven't been able to make it work.
Also, if any of the inputs are corner then the rest of the elements will be looped through. For example, if 1 is given then 2,6 and 7 and then 3,8,13,12,11 and so on. In essence all elements should be looped through.
Get the size of the array and row & column of the current number. Then get all indexes from [row-1,col-1] to [row+1,col+1]. Some of the values could be negative for border elements. So, exclude those
function surronding(array, n) {
const size = Math.sqrt(array.length),
index = n - 1,
row = Math.floor(index / size),
col = index % size,
output = []
for (let x = row - 1; x <= row + 1; x++) {
for (let y = col - 1; y <= col + 1; y++) {
if (x === row && y === col) // current
continue;
if (x < 0 || y < 0 || x >= size || y >= size) // out of range
continue;
output.push(arr[x * size + y])
}
}
return output;
}
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
console.log(...surronding(arr, 13))
console.log(...surronding(arr, 1))
console.log(...surronding(arr, 5))
One way could be to do a bucket sort of the values, where there is a bucket for each possible distance of the value to the given "center" value, and then output the buckets in order of distance:
function solve(n, root) {
const x = --root % n;
const y = (root - x) / n;
const result = Array.from({length: n}, () => []);
for (let i = 0; i < n*n; i++) {
if (i == root) continue;
result[Math.max(Math.abs(x - i % n), Math.abs(y - Math.floor(i / n)))].push(i+1);
}
return result.flat();
}
console.log(solve(5, 13));
You could take an approach with the length of the sides and an offset for the pivot element. as result, you get an index for a linear array.
const getAdjacent = (length, startI, startJ, offset = 0) => {
const indices = [];
offset++;
for (let i = startI - offset; i <= startI + offset; i++) {
for (let j = startJ - offset; j <= startJ + offset; j++) {
if (
i < 0 || i >= length || j < 0 || j >= length ||
(i !== startI - offset && i !== startI + offset && j !== startJ - offset && j !== startJ + offset)
) continue;
indices.push(i * length + j);
}
}
return indices;
};
console.log(...getAdjacent(5, 2, 2, 0));
console.log(...getAdjacent(5, 2, 2, 1));
You first need to transpose your value to line, column position.
const arr =
[ 1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12, 13, 14, 15,
16, 17, 18, 19, 20,
21, 22, 23, 24, 25 ]
function getAdjacents(number, arr)
{
let sQ = Math.sqrt(arr.length)
, n = number -1 // first position is zero
, C_ = n % sQ // column position
, R_ = (n - C_) / sQ // row position
;
return Array(3).fill().reduce((z,_,r)=>
[...z,...Array(3).fill().map((_,c)=>[r+R_-1,c+C_-1])],[])
.reduce((res,[rx,cx])=>
{
if ( rx>=0 && cx>=0
&& rx<sQ && cx<sQ
&& (rx!=R_ || cx!=C_) )
res.push((rx*sQ)+cx+1)
return res
},[])
}
console.log(13, '->', ...getAdjacents(13, arr) ) //-> 7 8 9 12 14 17 18 19
console.log( 1, '->', ...getAdjacents( 1, arr) ) //-> 2 6 7
console.log( 5, '->', ...getAdjacents( 5, arr) ) //-> 4 9 10
console.log(22, '->', ...getAdjacents(22, arr) ) //-> 16 17 18 21 23
.as-console-wrapper {max-height: 100%!important;top:0;}
I'm guessing that this fundamentally works the same way as #trincot's answer but I already had written most of it, hopefully it's okay to still post it.
const row_col_for_number = (square_side_size, number) => [
parseInt((number - 1) / square_side_size) + 1,
((number - 1) % square_side_size) + 1
];
const biggest_row_col_diff = ([a_row, a_col], [b_row, b_col]) =>
Math.max(Math.abs(a_row - b_row), Math.abs(a_col - b_col));
const distance_to_start = (square_side_size, start_row_col, number) =>
biggest_row_col_diff(
start_row_col,
row_col_for_number(square_side_size, number)
);
const sort_square_adjacency = (square_side_size, start_row_col) => (a, b) =>
distance_to_start(square_side_size, start_row_col, a) -
distance_to_start(square_side_size, start_row_col, b);
const doit = (square_side_size, start_number) =>
new Array(square_side_size * square_side_size)
.fill(0)
.map((_, i) => i + 1)
.sort(
sort_square_adjacency(
square_side_size,
row_col_for_number(square_side_size, start_number)
)
)
.slice(1);
console.log(...doit(5, 1));
console.log(...doit(5, 13));
// global variable
// accessible to all functions
var sol =
[[0, 7, 0, 2, 3, 8, 0, 0, 0],
[0, 0, 0, 7, 4, 0, 8, 0, 9],
[0, 6, 8, 1, 0, 9, 0, 0, 2],
[0, 3, 5, 4, 0, 0, 0, 0, 8],
[6, 0, 7, 8, 0, 2, 5, 0, 1],
[8, 0, 0, 0, 0, 5, 7, 6, 0],
[2, 0, 0, 6, 0, 3, 1, 9, 0],
[7, 0, 9, 0, 2, 1, 0, 0, 0],
[0, 0, 0, 9, 7, 4, 0, 8, 0]];
//this function prints the board
var printBoard = function () {
for (let row = 0; row < sol.length; row += 1) {
for (let col = 0; col < sol[row].length; col += 1) {
let id = 'r' + (row + 1) + (col + 1);
let elem = document.getElementById(id);
elem.innerHTML = sol[row][col];
}
}
};
function isValid(sol, row, col, k) {
for (let i = 0; i < 9; i++) {
const m = 3 * Math.floor(row / 3) + Math.floor(i / 3);
const n = 3 * Math.floor(col / 3) + i % 3;
if (sol[row][i] == k || sol[i][col] == k || sol[m][n] == k) {
return false;
}
}
return true;
}
var solve = function() {
for (let row = 0; row < 9; row++) {
for (let col = 0; col < 9; col++) {
if (sol[row][col] == 0) {
for (let k = 1; k <= 9; k++) {
if (isValid(sol, row, col, k) == true) {
sol[row][col] == '${k}';
if(solve() == true) {
return true;
} else {
sol[row][col] == 0;
}
}
}
return false;
}
}
}
return true;
}
printBoard();
I am having trouble debugging this. I keep getting an error message when I click on my solve button, which will take the grid and complete a sudoku puzzle: "Uncaught RangeError: Maximum call stack size exceeded". Looking at the file, it seems that my isValid() function, is causing the issues here. I think I am stuck in a continuous loop somewhere? Any help would be appreciated. It also says the error lies on lines 40 and 24, which are:
function isValid(sol, row, col, k) {
and
if (isValid(sol, row, col, k) == true) {
Please help, as I am not even a CS major and this is for a class requirement, and I am not exactly experience with this type of stuff. I tried to search for help thorugh other resources but it is just confusing me even more.
EDIT:
//global variable
//accesible to all functions
var sol =
[[0, 7, 0, 2, 3, 8, 0, 0, 0],
[0, 0, 0, 7, 4, 0, 8, 0, 9],
[0, 6, 8, 1, 0, 9, 0, 0, 2],
[0, 3, 5, 4, 0, 0, 0, 0, 8],
[6, 0, 7, 8, 0, 2, 5, 0, 1],
[8, 0, 0, 0, 0, 5, 7, 6, 0],
[2, 0, 0, 6, 0, 3, 1, 9, 0],
[7, 0, 9, 0, 2, 1, 0, 0, 0],
[0, 0, 0, 9, 7, 4, 0, 8, 0]];
//this function prints the board
var printBoard = function () {
for (let row = 0; row < sol.length; row += 1) {
for (let col = 0; col < sol[row].length; col += 1) {
let id = 'r' + (row + 1) + (col + 1);
let elem = document.getElementById(id);
elem.innerHTML = sol[row][col];
}
}
};
function isValid(sol, row, col, k) {
for (let i = 0; i < 9; i++) {
const m = 3 * Math.floor(row / 3) + Math.floor(i / 3);
const n = 3 * Math.floor(col / 3) + i % 3;
if (sol[row][i] == k || sol[i][col] == k || sol[m][n] == k) {
return false;
}
}
return true;
}
var solve = function(sol) {
for (let row = 0; row < 9; row++) {
for (let col = 0; col < 9; col++) {
if (sol[row][col] == 0) {
//set the check for the row and column
for (let k = 1; k <= 9; k++) {
if (isValid(sol, row, col, k) == true) {
sol[row][col] == k;
//check if its not true, then check the row and column again
if(solve() == true) {
return true;
} else {
sol[row][col] = 0;
}
}
}
return false;
}
}
}
return true;
};
printBoard();
You never change sol before recursively calling solve() again.
if (isValid(sol, row, col, k) == true) {
sol[row][col] == '${k}'; // <- does not update sol
if(solve() == true) {
return true;
} else {
sol[row][col] == 0; // <- does not update sol
}
}
When you find an option for k that is a valid you should update sol before calling solve() again. Otherwise you will create an endless recursive loop which will eventually exceed the maximum stack size and result in the error you receive.
Use the assignment operator (=) instead of the equality operator (==) to assign a new value. Furthermore '${k}' will result in the literal ${k} use backticks (`) if you want to use string interpolation. I don't see a reason to use a string here, simply assigning k would be sufficient.
if (isValid(sol, row, col, k) == true) {
sol[row][col] = k; // <- assign k to a cell in the matrix
if(solve() == true) {
return true;
} else {
sol[row][col] = 0; // <- reset the cell back to 0 if it cannot be solved
}
}
I would also suggest using guard clauses. Instead of nesting the whole body of the for-loop inside an if-statement, use a guard and skip to the next iteration with continue:
for (...) {
if (check) {
// code
}
}
Can be changed to:
for (...) {
if (!check) continue;
// code
}
This generally improves the code indention and readability.
My intention is to split an array using a separator and choose a limit of its splitting.
var arr = [89, 'sdf', 0, null, 0, true, 89, 0, 'sdf'];
var res = [];
while (arr.length) {
res.push(arr.splice(0, 2));
}
console.log(res)
For example: If 0 is the separator and 2 is the limit
arr.split(0, 2)
[[89, 'sdf'], [null]] //output
You could use indexOf and splice like this:
var arr = [89, 'sdf', 0, null, 0, true, 89, 0, 'sdf'];
function splitArray(arr, seperator, count) {
let result = [],
copy = arr.slice(), // if you don't want to mutate the original array
counter = 0;
while(counter < count && copy.length > 0) {
const index = copy.indexOf(seperator);
if(index !== - 1) {
result.push(copy.splice(0, index));
copy.shift(); // remove the seperator
}
else result.push(copy.splice(0)) // add the remaining items
counter++
}
return result
}
console.log(splitArray(arr, 0, 2))
console.log(splitArray(arr, 0, 3))
You could iterate the array and take a counter, which works as index for the result array and push the item into the result array of the counter.
function split(array, length, separator) {
var result = [],
count = 0,
i = 0;
while (count < length && i < array.length) {
if (array[i] === separator) {
count++;
i++;
continue;
}
result[count] = result[count] || [];
result[count].push(array[i++]);
}
return result;
}
console.log(split([89, 'sdf', 0, null, 0, true, 89, 0, 'sdf'], 2, 0));
Version with indexOf and slice.
function split(array, length, separator) {
var result = [],
p,
i = 0;
while ((p = array.indexOf(separator, i)) !== -1 && result.length < length) {
result.push(array.slice(i, p));
i = p + 1;
}
if (result.length < length) result.push(array.slice(i));
return result;
}
console.log(split([89, 'sdf', 0, null, 0, true, 89, 0, 'sdf'], 2, 0));
console.log(split([89, 'sdf', 0, null, 0, true, 89, 0, 'sdf'], 5, 0));
.as-console-wrapper { max-height: 100% !important; top: 0; }
you can use this one
var arrays = [], size = 2;
var arr = [89, 'sdf', 0, null, 0, true, 89, 0, 'sdf'];
while (arr.length > 0)
arrays.push(arr.splice(0, size));
my question is actually similar to: Extracting the most duplicate value from an array in JavaScript (with jQuery)
Solution (the one I found as the best, and slightly changed by me):
var arr = [3, 7, 7, 7, 7, 10, 10, 8, 5, 5, 5, 5, 20, 20, 1],
result = {},
max = 0,
res;
for( var i = 0, total = arr.length; i < total; ++i ) {
var val = arr[i],
inc = ( result[val] || 0 ) + 1;
result[val] = inc;
if( inc > max ) {
max = inc;
res = val;
}
}
alert(res);
I would like to add an extra which is : if we have, say two numbers with the same number of occurrences, how could we find the minimum of them (the above should alert 5 and not 7, which is the case)? The current solution works for getting only the first most duplicate found, but it does not deal with repetition.
Thanks!
Sort the array before you count the incidences:
var arr = [3, 7, 7, 7, 7, 10, 10, 8, 5, 5, 5, 5, 20, 20, 1];
function min_most_duplicate (arr) {
var result = {},
max = 0,
res;
arr = arr.slice(0); // make a copy of the array
arr.sort(function(a, b) { return (a - b); }); // sort it numerically
for( var i = 0, total = arr.length; i < total; ++i ) {
var val = arr[i],
inc = ( result[val] || 0 ) + 1;
result[val] = inc;
if( inc > max ) {
max = inc;
res = val;
}
}
return res;
}
min_most_duplicate(arr); // returns 5
This works because the way the for loop is written it's going to return the first one that it finds that has the most duplicates, so if the array is sorted, the smallest number will come first, so it'll be the one that the for loop finds.
This would work, example:
var arr = [3, 7, 7, 7, 7, 10, 10, 8, 5, 5, 5, 5, 20, 20, 1],
result = {},
max = 0,
res, key, min;
for (var i = 0, total = arr.length; i < total; ++i) {
var val = arr[i],
inc = (result[val] || 0) + 1;
result[val] = inc;
if (inc > max) {
max = inc;
res = val;
}
}
for (var i in result) {
if (result[i] === max) {
key = parseInt(i, 10);
min = min || key;
console.log(min)
if (min > key) {
min = key;
}
}
}
res = min;
alert(res);
let getMostDuplicated = array => {
let duplicated = '';
let max = 0;
for (let i = 0; i < array.length; i++) {
let counter = 0;
for (let j = 1; j < array.length - 1; j++) {
if (array[i] === array[j])
counter++;
}
if (counter > max) {
duplicated = array[i];
max = counter;
}
}
return duplicated;
};
let array = [3, 7, 7, 7, 7, 10, 10, 8, 5, 5, 5, 5, 20, 20, 1];
getMostDuplicated(array);