Credit Card Checker Challenge Project (JavaScript)

Consider:

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]       // even length

b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]   //  odd length

For the even length we can start at index 0 which will end at index 8.

For the odd length we can start at index 1 which will end at index 9.

In both cases we never touch the last element.

If n is our array’s length,

n = arr.length

our starting position can be computed to be,

start = n % 2

Now we have a starting point,

for (let i = start; i < n; i += 2) {

}

That’s one way, at least. Most people work backwards through the array but I like this way, better.

thanks mtf. The godfathere of the forums as ever!

1 Like

Can someone enlighten me what did I do wrong? I just can’t get the last step correct :smiling_face_with_tear: :smiling_face_with_tear:

Also, I have two questions that I cannot figure out:

  1. How can I show the original card numbers instead of the augmented arrays of numbers?
  2. Is it possible to show the names (valid4) instead of the their arrays in the ‘findInvalidCards(batch)’ in step 4?
function validateCred(arr) {
  let doubledArray = []; //2x for certain digits
  for (let i = arr.length - 1; i >= 0; i--) {
    if (i === arr.length - 1) {
      arr[i] *= 1;
    } else if (i === arr.length - 2 || (arr.length - i) % 2 === 0) {
      arr[i] *= 2;
    }
    doubledArray.push(arr[i]);
  }
  //console.log(doubledArray)
  let finalArray = []; // Minus 9 for those certain digits
  for (let j = 0; j < doubledArray.length; j++) {
    if (doubledArray[j] > 9) {
      doubledArray[j] -= 9;
    }
    finalArray.push(doubledArray[j]);
  }
  // console.log(finalArray)
  let sum = finalArray.reduce((a, b) => a + b, 0); //final sum
  // console.log(sum)
  if (sum % 10 == 0) {
    //final output
    return "valid";
  } else {
    return "invalid";
  }
}

function findInvalidCards(batch) {
  let invalidCards = [];
  for (let k = 0; k < batch.length; k++)
    if (validateCred(batch[k]) === "invalid") {
      invalidCards.push(batch[k]);
    }
  return invalidCards;
}
//console.log(findInvalidCards(batch));

let index = findInvalidCards(batch);
console.log(index)

function idInvalidCardCompanies(index) {
  let companies = [];
  for (let m = 0; m < index.length; m++) {
    switch (index[m][0]) {
      case 3:
        if (!companies.includes("Amex (American Express")) {
          companies.push("Amex (American Express");
        }
      case 4:
        if (!companies.includes("Visa")) {
          companies.push("Visa");
        }
      case 5:
        if (!companies.includes("Mastercard")) {
          companies.push("Mastercard");
        }
      case 6:
        if (!companies.includes("Discover")) {
          companies.push("Discover");
        }
      default:
        if (!companies.includes("Company not found")) {
          companies.push("Company not found");
        }
    }
  }
  return companies;
}
console.log(idInvalidCardCompanies(index))

Hi, guys. This was an interesting project, but I need help with step 4, the findInvalidCards() function.

I made it, and it mostly seems to work as expected, but there is a specific step where it is somehow pulling the summed arrays in and pushing those to output instead of the originals.

If you look at Line 73-74 in the gist, basically what appears to be happening is that the testSet is somehow having its values re-assigned. I think this may be due to some quirk of the validateCred() function but I’ve spent all day so far staring at this and I can’t figure out what’s going on.

i have the exact same problem. hope someone can help.

You changed the original array, not a copy.

your code
function validateCred(inputArray)
{
	let everyOther = true; //we'll use this to go through every other element (not each one)
	for (let i = inputArray.length-2; i >= 0; i--) //we start at the second-to-last element in the array
	{
		if (everyOther === true)
		{
			inputArray[i] *= 2; //multiply the element by two.  if the result is higher than 9, subtract 9 from it.
			if (inputArray[i] > 9)
			{
				inputArray[i] -= 9;
			}
		}
		everyOther = !everyOther; //flip everyOther
	}
	let inputSum = sumArray(inputArray);
	if (inputSum % 10 === 0)
	{
		return true;
	} else
	{
		return false;
	}
}

Notice that the validateCred function has a parameter inputArray
and since inputArray is an array, which is a kind of object,
changing inputArray changes the array used as an argument for the validateCred function.
(inputArray is another reference to the same object, its not a new object… it goes to the same location in the memory as the original array.)

One way to avoid the function causing changes the original array is to make a copy of the array and then change that copy.
For example,

function validateCred(originalArray)
{
     const inputArray = Array.from(originalArray); // inputArray is a copy of originalArray
2 Likes

Hello, this is my solution
took some time to solve this project :grinning:

That did the trick, thank you. I guess my understanding of arrays is still elementary.

Hello Zachary,
I know that the posting and request you made was back in February 2020, but nonetheless I’m going to throw in an explanation from my understanding of it. This is just by eye-balling the line from the solution you pasted (I’ve not seen the rest of the solution code). My solution works, but I did it slightly differently.

This line of code (array.length - 1 - i) % 2 === 1)
is doing the following:

  1. get the length of the array and start traversing it backwards (due to length being decreased by i)
  2. Does a modulus operation on the length so that odd element index positions return true.
  3. with each iteration it decreases index location by i so that each index location is tested for evennes/oddness
    Note - the For loop variable i is decreasing by 1 for each interation of the loop until its value is less than zero/0.
  4. Based on this logic you can then say/code that odd index locations values are not doubled, but even ones are doubled.
  5. Which means that the check digit value (last element from right to left) would not be doubled, but the following index element value would be doubled.

This would satisfy the requirement to double the value of every other element in the array (not including the check digit) traversing from right to left (using a For Loop that goes from max length of the array to first element of the array)

I hope that this helps you and anyone else who might be wondering about the same thing about the
(array.length - 1 - i) % 2 === 1) line and what it’s actually doing or being used for.

Kind Regards,
Lenpoyau

This one definitely took longer than expected, but nonetheless. Fun and glad I did it!
Completed the extension challenge as well!

Github Repo: GitHub - daryldelrosario/creditcard-checker: Using JavaScript to validate credit card numbers
Code Demo:
cc-checker-live

Feedback and connections welcomed!
Happy coding!

1 Like

Changing arr (the parameter for the validateCred function changes the original array (because an array is an object, not a primitive type).
So when you do
arr[i] *= 2;
you’re changing the original array, not a copy of it.

You can fix that by avoiding changing the original array; and using copies of stuff in the array or a copy of the array instead.

function validateCred(arr) {
  let doubledArray = []; //2x for certain digits
  for (let i = arr.length - 1; i >= 0; i--) {
    let x = arr[i]; // copy number in arr[i] to x
    if (i === arr.length - 1) {
      x *= 1;
    } else if (i === arr.length - 2 || (arr.length - i) % 2 === 0) {
      x *= 2;
    }
    doubledArray.push(x);
  }

you saved my day. thank you so much!

My Solution:

Hi all,

Here’s my solution. I initially implemented the validateCred() function using a for loop. But wanted to challenge myself to use an iterator so used .reduceRight() which seemed perfectly suited to this task. (I tried .reduce() first after reversing the array but it proved to be too complicated so gave up on it). Took an awful lot of testing in console before it worked. I left the for loop in the comment, I think it still looks neater than .reduceRight(). Any comments welcome!

As for the last “extra challenge” - “Create a function that will convert invalid numbers into valid numbers.” - I’m not sure what they mean, modify an invalid number somehow until it becomes valid?

I assume they mean changing the last digit (the check digit) so that the card number would be valid.

// global variables
const invalid_Carts_checked = [];
const companies_Invalid_carts_Checked = [];

// function that checks card validity
const validateCred = array => {
 const newArr = array.slice(0, -1); // array of 'array' without last element
 const checkArr = newArr.filter((e, i) => i % 2 === 0); // every even item of newArr
 const otherArr = newArr.filter((e, i) => i % 2 === 1); // every odd item of newArr
 let modArr = [];
 let sumOfArrays = 0;

  for (let i = 0; i <= checkArr.length - 1; i++) { 

    if ((checkArr[i] * 2) > 9) {
     modArr.push((checkArr[i] * 2) - 9);
    } else {
      modArr.push(checkArr[i] * 2);
    }
  }

  modArr = modArr.concat(otherArr, array[array.length-1]);
  
  for (let i = 0; i < modArr.length; i++) { // calculating sum of concatenated modArr
    sumOfArrays += modArr[i];
  }
  return sumOfArrays % 10 === 0 ? true : false; // checking if creditcard number is valid
}



// mass check function to find invalid carts out of a batch
const findInvalidCards = batch => {
  let check = invalid_Carts_checked;

  for (let i = 0; i < batch.length; i++) {
    validateCred(batch[i]) === false ? check.push(batch[i]) : false; 
  }
  return check;
}


findInvalidCards(batch);


// identifies credit card companies for invalid_Carts_checked
const idInvalidCardCompanies = checkedBatch => {
  let companies = companies_Invalid_carts_Checked;

  for (let i = 0; i < checkedBatch.length; i++) {

      switch (checkedBatch[i][0]) {
        case 3:
        companies.push('Amex');
        break;

        case 4:
        companies.push('Visa');
        break;

        case 5:
        companies.push('Mastercard');
        break;

        case 6:
        companies.push('Discover');
      }
    }
    return companies.filter((item, index) => companies.indexOf(item) === index); // duplicate filtered
}

function validateCred(arr) {
arr.reverse();
let sum = arr[0];
console.log(arr);
console.log(arr.length);
for (i = 2; i < arr.length; i + 2) {
sum = sum + doubleGreaterThanNine(arr[i]);
console.log(sum);
}
for (j = 1; j < arr.length; j + 2) {
sum = sum + arr[j];
console.log(sum);
}
if (sum % 10 === 0) {
return true;
} else if (sum % 10 !== 0) {
return false;
}
}

Wondering why my loop appears to be infinite? Each time I click run it spins forever.

bravo! I’ve liked this idea

let doubleFactor = cardLength % 2;
...
i % 2 === doubleFactor
1 Like

Really appreciate it, thank you! @clipklop

You’re not actually increasing the value of i or j in your loops.
(The value of i was always 2, so it became an infinite loop.)

for (i = 2; i < arr.length; i + 2) {
should be
for (let i = 2; i < arr.length; i = i + 2) {

Notice that i + 2 should be i = i + 2 or i += 2 so that the value of i changes (increases by 2) for each iteration.

Similarly,
for (j = 1; j < arr.length; j + 2) {
should be
for (let j = 1; j < arr.length; j = j + 2) {
or something similar.

1 Like