Divide matrix to sub matrices (Javascript) [closed] - javascript

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I need this for a codewars challenge to make my code DRY
I have an array of arrays, lets say a 9x9 matrix.
const sudokuTest2= [
[5, 3, 4, 6, 7, 8, 9, 1, 2],
[6, 7, 2, 1, 9, 0, 3, 4, 9],
[1, 0, 0, 3, 4, 2, 5, 6, 0],
[8, 5, 9, 7, 6, 1, 0, 2, 0],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 0, 1, 5, 3, 7, 2, 1, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 0, 0, 4, 8, 1, 1, 7, 9],
];
How can I divide it automatically into 9 equal areas, something which results from the following sample code:
const areas = [];
areas[0] = sudokuTest2[0]
.slice(0, 3)
.concat(sudokuTest2[1].slice(0, 3))
.concat(sudokuTest2[2].slice(0, 3));
areas[1] = sudokuTest2[3]
.slice(0, 3)
.concat(sudokuTest2[4].slice(0, 3))
.concat(sudokuTest2[5].slice(0, 3));
areas[2] = sudokuTest2[6]
.slice(0, 3)
.concat(sudokuTest2[7].slice(0, 3))
.concat(sudokuTest2[8].slice(0, 3));
areas[3] = sudokuTest2[0]
.slice(3, 6)
.concat(sudokuTest2[1].slice(3, 6))
.concat(sudokuTest2[2].slice(3, 6));
areas[4] = sudokuTest2[3]
.slice(3, 6)
.concat(sudokuTest2[4].slice(3, 6))
.concat(sudokuTest2[5].slice(3, 6));
areas[5] = sudokuTest2[6]
.slice(3, 6)
.concat(sudokuTest2[7].slice(3, 6))
.concat(sudokuTest2[8].slice(3, 6));
areas[6] = sudokuTest2[0]
.slice(6, 9)
.concat(sudokuTest2[1].slice(6, 9))
.concat(sudokuTest2[2].slice(6, 9));
areas[7] = sudokuTest2[3]
.slice(6, 9)
.concat(sudokuTest2[4].slice(6, 9))
.concat(sudokuTest2[5].slice(6, 9));
areas[8] = sudokuTest2[6]
.slice(6, 9)
.concat(sudokuTest2[7].slice(6, 9))
.concat(sudokuTest2[8].slice(6, 9));
For sure I could use some nested loops, but I'm curious if there is any solution with array methods.
What will be the best solution, what do you think?

You could take generate the wanted 3x3 parts by using a nested mapping.
const
sudoku = [[5, 3, 4, 6, 7, 8, 9, 1, 2], [6, 7, 2, 1, 9, 0, 3, 4, 9], [1, 0, 0, 3, 4, 2, 5, 6, 0], [8, 5, 9, 7, 6, 1, 0, 2, 0], [4, 2, 6, 8, 5, 3, 7, 9, 1], [7, 1, 3, 9, 2, 4, 8, 5, 6], [9, 0, 1, 5, 3, 7, 2, 1, 4], [2, 8, 7, 4, 1, 9, 6, 3, 5], [3, 0, 0, 4, 8, 1, 1, 7, 9]],
areas = Array
.from({ length: 3 })
.flatMap((_, i) => Array
.from(
{ length: 3 },
(__, j) => Array
.from({ length: 3 })
.flatMap((___, k) => sudoku[j * 3 + k].slice(i * 3, (i + 1) * 3)
)
));
areas.forEach(a => console.log(...a));

This can be done in with single forEach method. The idea behind this is dynamic indexing.
const matrix = [ [5, 3, 4, 6, 7, 8, 9, 1, 2], [6, 7, 2, 1, 9, 0, 3, 4, 9], [1, 0, 0, 3, 4, 2, 5, 6, 0], [8, 5, 9, 7, 6, 1, 0, 2, 0], [4, 2, 6, 8, 5, 3, 7, 9, 1], [7, 1, 3, 9, 2, 4, 8, 5, 6], [9, 0, 1, 5, 3, 7, 2, 1, 4], [2, 8, 7, 4, 1, 9, 6, 3, 5], [3, 0, 0, 4, 8, 1, 1, 7, 9],];
let areas = new Array(9).fill([]);
matrix.forEach((numbers, idx)=> {
let segment = Math.floor(idx / 3);
areas[segment] = [...areas[segment], ...matrix[idx].slice(0, 3)];
areas[segment + 3] = [...areas[segment + 3], ...matrix[idx].slice(3, 6)];
areas[segment + 6] = [...areas[segment + 6], ...matrix[idx].slice(6, 9)];
})
areas.forEach(area => console.log(...area));

Related

Credit card checker with Luhn algorith javascript

I am currently working on codeacademy's 'Credit Card Checker' using Luhn algorithm, however my code is returning false on valid arrays(which should return). Could you help me resolve the issue?
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9];
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6];
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5];
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6];
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3];
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4];
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5];
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4];
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4];
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9];
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3];
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3];
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3];
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
// Add your functions below:
const validateCred = arr => {
let totalSum = 0;
let revList = arr.reverse();
for (let i = 0; i < revList.length; i++) {
let calcAmount = revList[i];
if (i !== 0 && i%2 === 0) {
calcAmount = revList[i] * 2;
if (calcAmount > 9 ) {
calcAmount -= 9;
totalSum += calcAmount;
} else {
totalSum += calcAmount;
}
} else {
totalSum += revList[i];
}
}
return (totalSum%10 === 0 ? true : false);
};
console.log(validateCred(valid3))
console.log(validateCred(valid4))
console.log(validateCred(valid5))
A simple mistake, check if (i%2 === 1) {, algorithm needs to multiply 2 for every second elements
arr.reverse() is also bad idea, original array is changed.
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9];
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6];
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5];
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6];
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3];
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4];
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5];
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4];
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4];
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9];
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3];
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3];
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3];
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
// Add your functions below:
const validateCred = arr => {
let totalSum = 0;
let revList = arr.reverse();
for (let i = 0; i < revList.length; i++) {
let calcAmount = revList[i];
if (i%2 === 1) {
calcAmount = revList[i] * 2;
if (calcAmount > 9 ) {
calcAmount -= 9;
totalSum += calcAmount;
} else {
totalSum += calcAmount;
}
} else {
totalSum += revList[i];
}
}
return(totalSum%10 === 0 ? true : false);
};
batch.forEach(c => console.log(validateCred(c)));
Rewrite and fixed.
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9];
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6];
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5];
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6];
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3];
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4];
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5];
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4];
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4];
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9];
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3];
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3];
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3];
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
function luhnCheck(num) {
let digit, j, len, odd = true, sum = 0
const digits = (num + '').split('').reverse()
for (j = 0, len = digits.length; j < len; j++) {
digit = parseInt(digits[j], 10)
if ((odd = !odd)) digit *= 2
if (digit > 9) digit -= 9
sum += digit
}
return sum % 10 === 0
}
batch.forEach((item) => {
let number = item.join('')
console.log(number, luhnCheck(number))
})
Ideally, you should pass it in as a string and let the function do the splitting (separation of concerns) as in a real app your want to do various things on the entered number before running luhn like.. cardTypeFromNumber (visa, maestro, dankort, mastercard, amex, dinersclub, discover, chinaunionpay (doesn't use luhn), jcb mostly have all different lengths you wouldn't want to run luhn until you validate the length and format), formatCardNumber, validateCardExpiry, validateCardCVC to name a few.
The Luhn algorithm is explained on Wikipedia. Others have answered the question, this is just a different implementation.
function luhnCheck(cardNumber) {
let nums = cardNumber.split('').reverse();
let checkValue = nums.shift();
let luhnSum = nums.reduce((sum, n, i) => {
let val = n*(i % 2? 1 : 2);
sum += val > 9? val - 9 : val;
return sum;
}, 0);
return checkValue == 10 - (luhnSum % 10);
}
['4539677908016808', // valid1
'5535766768751439', // valid2
'4532778771091795', // invalid1
'5795593392134643', // invalid2
'344801968305414', // mystery1
'5466100861620239', // mystery2
].forEach(cardNum =>
console.log(luhnCheck(cardNum))
);

Get 3x3 blocks from 9x9 2d array as String

I am learning Javascript and currently found myself with the following problem. I need to get each individual 3x3 block of a 9x9 2d array as a string, separated by commas.
What I mean is, for example, let's say I have the following array:
var 2dArray = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9] ]
The result should be something like 535671192,678195342, 912348657, ... and so on, until the string is made of all the 3x3 blocks.
I thought that making nested for loops would be the best approach, but got confused along the way and I would appreciate your help.
Thank you.
You can use two loops to iterate over the positions of all the possible top left corners and another two loops to get all the elements in that square.
var arr = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9]
];
let res = [];
for (let i = 0; i < 9; i += 3) {
for (let j = 0; j < 9; j += 3) {
let curr = "";
for (let k = 0; k < 3; k++) {
for (let l = 0; l < 3; l++) {
curr += arr[i + k][j + l];
}
}
res.push(curr);
}
}
console.log(res);
The issue can also be solved by loops but it's good practice to solve it using the Array.map() function.
let arrayRow = "";
const resultArray = Array2d.map((element, index) => {
return arrayRow + element.map((element, i) => {
return element.toString();
});
});
you should try like this too.
var arr = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9]
];
let res = [];
let i = 0,j = 0;
let justOneStr = "";
while(i < 9 && j < 9){
justOneStr += arr[i][j];
if(i % 3 == 2 && j % 3 == 2){
res.push(justOneStr);
justOneStr="";
}
if((j % 9 == 8 || j % 3 == 2) && i % 3 != 2){
j -= 3;
i += 1;
}
else if(j % 9 == 8 && i % 3 == 2){
j -= 9;
i += 1;
}
else if(i % 3 == 2 && j % 3 == 2){
i -= 2;
}
j++;
}
console.log(res);
Here's a fairly straightforward nested reduce() that returns an array of matrices of the specified size. It touches each element once, and uses the coordinates in the passed matrix to determine which sub-matrix and sub-matrix row to accumulate into.
const
matrix = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9]],
subdivide = (matrix, width, height) => {
return matrix.reduce((acc, row, i) => {
row.reduce((_acc, x, j, row) => {
const grid = Math.floor(j / width) + Math.floor(i / height) * (Math.ceil(row.length / width));
const gridRow = i % height;
_acc[grid] ??= [];
(_acc[grid][gridRow] ??= []).push(x);
return _acc;
}, acc)
return acc;
}, [])
},
subdividedmatrix = subdivide(matrix, 3, 3);
// log submatrices
subdividedmatrix.forEach(m => console.log(JSON.stringify(m)));
// map to strings
console.log(subdividedmatrix.map(submatrix => submatrix.flat().join('')))
.as-console-wrapper { max-height: 100% !important; top: 0; }

Slicing 2d array in Javascript

This is the Python code which I want to convert to Javascript!
y[i] = x[i][:j] + x[i][j] + x[i][j + 1:]
I tried using the slice function but I cannot correctly implement it for a 2d array.
So that's just some python fancy work for list comprehension but I believe you could accomplish such a thing with:
const x = [
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9]
];
var y = new Array(81);
for (i = 0; i < x.length; i++) {
var row = new Array(20);
for (j = 0; j < x.length; j++) {
row.push(x[i].slice(j).concat(x[i][j]).concat(x[i].slice(0, j+1)))
}
y.push(row);
}
for(k = 0; k < y.length; k++) {
console.log(y[k]);
}
I'm not exceptionally good with javascript, but let me know if that helps.
-Or-
provide some more input/output so I can test with, any additional code, what you've tried or what you're expected output may look like.

remove duplicate elements in proceeding arrays inside array of arrays

We have an array of arrays like this:
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14]
];
There may be duplicate elements in each array and that's fine.
But I'm after a proper solution to remove duplicate elements in each set comparing to lower sets!
So as we have a 0 in the first array and the last array, we should consider the 0 in last one a duplication and remove it...
the desired result would be:
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[12],
[14]
It's a confusing issue for me please help...
You could collect the values in an object with index as value, and filter for values who are at the same index.
const
arrays = [[0, 1, 2, 3, 4, 4, 4, 4], [5, 6, 7, 8, 9, 10, 11, 11], [2, 7, 10, 12], [0, 7, 10, 14]],
seen = {},
result = arrays.map((array, i) => array.filter(v => (seen[v] ??= i) === i));
result.forEach(a => console.log(...a));
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[4, 4, 5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14]
]
let filtered = arrays.map((row, i) => {
// concat all previous arrays
let prev = [].concat(...arrays.slice(0, i))
// filter out duplicates from prev arrays
return row.filter(r => !prev.includes(r))
})
console.log(filtered)
We can do this using Array#reduce and maintain a seen Set, which will have all visited numbers from each array.
Once you iterate over an array you push all visited elements in the seen Set, then push a new array filtered by the elements not in the seen Set:
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14]
];
const removeDupsInSibling = (arr) => {
let seen = new Set();
return arr.reduce((acc, a)=> {
const f = a.filter(v => !seen.has(v));
seen = new Set([...seen, ...a]);
acc.push(f);
return acc;
}, []);
}
console.log(removeDupsInSibling(arrays));
There are plenty of inefficient ways to do this, but if you want to do this in O(n), then we can make the observation that what we want to know is "which array a number is in". If we know that, we can run our algorithm in O(n):
for every element e in array at index i:
if index(e) == i:
this is fine
if index(e) < i:
remove this e
So let's just do literally that: we allocate an object to act as our lookup, and then we run through all elements:
const lookup = {};
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14]
];
const reduced = arrays.map((array, index) => {
// run through the elements in reverse, so that we can
// safely remove bad elements without affecting the loop:
for(let i=array.length-1; i>=0; i--) {
let value = array[i];
let knownIndex = (lookup[value] ??= index);
if (knownIndex < index) {
// removing from "somewhere" in the array
// uses the splice function:
array.splice(i,1);
}
}
return array;
});
console.log(reduced);
For an alternative, where the loop+splice is taken care of using filter, see Nina's answer.
Simple, clean and high performance solution:
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14]
];
const duplicates = {};
const answer = arrays.map( (array, level) => {
return array.filter( el => {
if ( duplicates[el] < level ) {
// return nothing; fine
} else {
duplicates[el] = level;
return el
}
})
});
console.log(JSON.stringify(answer))
here is on-liner and less-readable form:
const d = {}, arrays = [ [0, 1, 2, 3, 4, 4, 4, 4], [5, 6, 7, 8, 9, 10, 11, 11], [2, 7, 10, 12], [0, 7, 10, 14]];
const answer = arrays.map((a,l)=> a.filter(el=> d[el]<l ? 0 : (d[el]=l,el)));
console.log(JSON.stringify(answer))
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14],
];
const output = arrays.reduce(
({ output, set }, current, i) => {
output[i] = current.filter((num) => !set.has(num));
[...new Set(output[i])].forEach((num) => set.add(num));
return { output, set };
},
{ output: [], set: new Set() }
).output;
console.log(output);
Gets the exact output you want:
[
[
0, 1, 2, 3,
4, 4, 4, 4
],
[
5, 6, 7, 8,
9, 10, 11, 11
],
[ 12 ],
[ 14 ]
]

Passing an array to a function parameter and getting values from nested array

I got stuck while practicing credit card checker practice.
My code:
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8]
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9]
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6]
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5]
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6]
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5]
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3]
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4]
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5]
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4]
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4]
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9]
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3]
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3]
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3]
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5]
// Add your functions below:
const validateCred = (array)=> {
let tempArrSub = []; //Holds values of the 9 subtracted from doubled elements bigger than 9
let tempArr = array; //Copies the values of the array passed into parameters
tempArr.pop();
tempArr.reverse();
for (let i = tempArr.length-1; i >=0; i-=2){ //Doubles every two elements from right to left
tempArr[i] *= 2;
}
for (let k = 0; k < tempArr.length; k++) { //Subtract 9 from every second element (right to left) if bigger than 9
if (tempArr[k] > 9){
tempArrSub.push(tempArr[k] - 9);
}
else {
tempArrSub.push(tempArr[k]);
}
}
let tempArrSum = 0;
for (let m = 0; m < tempArrSub.length; m++){ //Calculates the sum of all elements in the array
tempArrSum += tempArrSub[m];
}
tempArrSum += array.pop(); //Adds the last digit of initial array to the sum
if (tempArrSum % 10 === 0) { //Returns true if the sum is divisible by 10
return true;
}
else {
return false;
}
} //End Of Function
const findInvalidCards = (nestedArray) => {
let invalidCards = [];
let validCards = [];
for (let a = 0; a < nestedArray.length; a++){
if ( validateCred(nestedArray[a]) == true ) {
validCards.push(nestedArray[a]);
}
else {
invalidCards.push(nestedArray[a]);
}
}
console.log("Invalid cards: \n" + invalidCards);
console.log("Valid cards: \n" + validCards);
}
I checked all arrays one by one passing as an argument to validateCred() function. It's working and returning true or false for each credit card.
In order to automate process I wanted findInvalidCards() to find valid or invalid cards by calling validateCred() function inside itself and returning boolean value for each card.
Here I got stuck. Because it is returning true for the 1st card and false for the remaining cards. I've been playing with the code for the whole day, but I could not move forward. I rely on your help. Thanks in advance
I don't know if is it helpful to you or not. But I rewrite your code with an optimal way.
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8]
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9]
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6]
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5]
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6]
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5]
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3]
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4]
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5]
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4]
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4]
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9]
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3]
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3]
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3]
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
isValidCard = (array) => {
let copy = [...array];
const last = copy.pop();
copy.reverse();
copy = copy.map((dig, i) => ((i % 2 === 0 ? dig * 2 : dig)));
copy = copy.map(dig => (dig > 9 ? dig - 9 : dig));
const sum = copy.reduce((acc, curr) => acc + curr);
return ((sum + last) % 10 === 0);
}
findInvalidCards = (array) => {
const validList = [];
const invalidList = [];
array.forEach(card => {
if (isValidCard(card)) {
validList.push(card);
} else {
invalidList.push(card);
}
});
console.log('valid cards', validList);
console.log('invalid cards', invalidList);
}
findInvalidCards(batch);
I think your issue is this line:
let tempArr = array; //Copies the values of the array passed into parameters
According to your comment you want to copy the array, but just assigning it to another variable does not copies it. In order to copy just so something like this:
let copy = array.slice(0);
/* or (will not work for large arrays) */
let copy = [...array];
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9];
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6];
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5];
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6];
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3];
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4];
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5];
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4];
const invalidCredit = [invalid1, invalid2, invalid3, invalid4, invalid5]
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4];
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9];
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3];
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3];
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3];
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
// Add your functions below:
const validateCred = (arr) => {
let reversedArr = arr.reverse();
let oddOccurrences = [];
reversedArr.forEach((value, i) => i % 2 ? oddOccurrences.push(value *= 2) : oddOccurrences.push(value));
const checking = oddOccurrences.map((greater) => (greater > 9 ? (greater -= 9) : greater));
const sum = checking.reduce((acc, num) => {
return acc + num
}, 0)
// Conditional check
if (sum % 10 === 0)
return 'valid'
else return 'invalid'
}
console.log(validateCred([4, 5, 3, 9, 6, 8, 9, 8, 8, 7, 7, 0, 5, 7, 9, 8]));
findInvalidCards = (newArr) => {
const invalidList = [];
const validList = [];
for (let i = 0; i < newArr.length; i += 15) {
// inner loop
for (let j = 0; j < newArr.length; j++) {
validateCred(newArr[j]) === 'invalid' ? invalidList.push(newArr[j]) : validList.push(newArr[j]);
}
};
console.log(invalidList)
}
findInvalidCards(batch);

Categories

Resources