Credit Card Checker - trouble looping the batch array and luhn algorithm

It uses a switch to determine what company a card belongs to based on the first digit of the card number.

The assignment is to push each company name only once. So in order to do so, it checks using an if statement and the function indexOf if the company name is already in the array of companies. If it is not the indexOf function returns a “-1” thus causing the boolean checker to execute companies.push(‘name’);

2 Likes

“The more I know, the more I realize I know nothing.”
― Socrates
:smile:

1 Like

I’d like to know what you think about my solution? I’m new to Javascript and was wondering if this is the best way to do it?

// 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 = card => {
    let sumOfCredit = 0;
    for (let i = card.length - 1; i >= 0; i--) {
        let currentVal = card[i];
        if ((card.length - 1 - i) % 2 === 0) {
            sumOfCredit += currentVal;
        }
        else {
            let doubleNum = currentVal * 2;
            if (doubleNum > 9) {
                sumOfCredit = sumOfCredit + doubleNum - 9;
            } else {
                sumOfCredit += doubleNum;
            }
        }
    }
    if (sumOfCredit % 10 === 0) {
        return true;
    }
    else {
        return false;
    }
};

const findInvalidCards = cards => {
    const validAndInvalid = [[], []];
    for (let i = 0; i < cards.length; i++) {
        let card = cards[i];
        if (validateCred(card)) {
            validAndInvalid[0].push(card);
        } else {
            validAndInvalid[1].push(card);
        }
    }
    return validAndInvalid;
};

// console.log(validateCred(valid3));
// console.log(findInvalidCards(batch));

const idInvalidCardCompanies = invalidCards => {
    const companies = [];
    for (let i = 0; i < invalidCards.length; i++) {
        let firstDigit = invalidCards[i][0];
        switch (firstDigit) {
            case 3:
                if (companies.indexOf("Amex") === -1) {
                    companies.push("Amex");
                }
                break;
            case 4:
                if (companies.indexOf("Visa") === -1) {
                    companies.push("Visa");
                }
                break;
            case 5:
                if (companies.indexOf("Mastercard") === -1) {
                    companies.push("Mastercard");
                }
                break;
            case 6:
                if (companies.indexOf("Discover") === -1) {
                    companies.push("Discover");
                }
                break;
            default:
                companies.push("Company not found");
        }
    }
    return companies;
}


console.log(idInvalidCardCompanies([invalid1]));
console.log(idInvalidCardCompanies([invalid2]));
console.log(idInvalidCardCompanies(batch));

there are many ways to judge, there won’t be a best

and there are many ways to do it, and many ways to write the same thing


your code does give off the impression that you know what you’re doing, that you’re in control. everything in there is there for a reason.

there are things i’d change though:

the first of which is:

what this does is: if the result is true, then return true, otherwise return false

…just return the result itself.


then, without reading any of the code, but looking at the shape of it:

    for (let i = card.length - 1; i >= 0; i--) {
        let currentVal = card[i];
        if ((card.length - 1 - i) % 2 === 0) {
            sumOfCredit += currentVal;
        }
        else {
            let doubleNum = currentVal * 2;
            if (doubleNum > 9) {
                sumOfCredit = sumOfCredit + doubleNum - 9;
            } else {
                sumOfCredit += doubleNum;
            }
        }
    }

it’s wandering off to the right side.
sometimes the idea of something really is nested. but if not, then i try to hug the left side.

i might make two loops, one for odd indices, one for even. in your code one of them is nested inside the other, they could be done one after the other instead. it would be a bit longer, but each part would be simpler.
or make a copy of the array, and double every other in the array, then get the sum with a separate function


i very rarely like switches.
there are also several things being done in that function:

classifying company
iteration
unique

in my eyes, those are three totally separate things, and this function should only be doing one of them, the classification of a single card.

  const knownCompanies = {
    3: 'Amex (American Express)',
    4: 'Visa',
    5: 'Mastercard',
    6: 'Discover'
  }

rather than spreading this information out, they can be put in a data structure, and then one can look up the number.

iteration can then be done with map. you might not have been introduced to it yet, but it’s a function that does a common task: applying an operation to each value in an array, producing an array containing each result. in this case, an array of cards where each card should be classified, producing an array of companies

unique can be a totally separate function applied afterwards - keeping only unique items is something that many different things might do and it would be a bit silly if each of them implements this functionality over and over. breaking it out into its own function makes the remaining code simpler.

Thanks for the insight! I def like the returning the condition instead of using an if else. I know I can do that but I didn’t think of it at the time. I’ll look into the mapping but it wasn’t introduced yet in this section that I did but I’ll be getting to it

This is great. I’ve worked through it and implemented it but when I run the function on the valid1, 2, 3, 4 or 5 it still returns false. Only the mysteri1 returns true.

Am I missing something or should the valid arrays not be deemed as, well, valid?

Here’s the code that returns false on console.log(validateCred(valid1)); :

const validateCred = card => { //this takes the input of a card
    let cardInverted = card.slice().reverse(); //this uses .slice to make a copy of the array and .reverse to, well, reverse the order of card digits
    for (let digit = 0; digit < cardInverted.lenght; digit++) { // this loops through the index of digits
        if (digit % 2 != 0) { // this picks the uneven numbers using Modulo 2
            cardInverted[digit] = cardInverted[digit] * 2; // doubles the value of the array at each uneven digit
            if (cardInverted[digit] > 9) { // if the values is higher then 9
                cardInverted[digit] -= 9;  // then subtract 9 and assign it to the variable
            }
        }
    }
    let sum = cardInverted.reduce((a, b) => a + b, 0); // uses .reduce to sum all the numbers in the array
    if (sum % 10 == 0) { // checks if the 10 is equal to 0 (the Luhn algorithm)
        return true;
    } else {
        return false; 
    }
}

console.log(validateCred(valid1));```

What happens if you check them manually? (And you may want to re-read the instructions before you do to be sure)

If you get a different result, where does your code act differently? You may want to use console.log to write out what is being done so that you can observe

The for loop is skipped because your cardInverted.length call is wrong. You made a typo lenght causing an undefined. Which in turn causes the running condition 0 < cardInverted.lenght to stop the for loop immediately.

Debugging at its finest :stuck_out_tongue: . Change the typo and you are good to go!

Beginners (and myself too for that matter) are often blind to such things. Better if the strategy of finding it doesn’t involve staring at the code. Interacting with it/observing will lead to -> why doesn’t anything print from within this loop -> oh it doesn’t run at all -> does this function run at all? -> yes -> what controls how much this loop runs? -> the three semicolon-separated parts in a for-statement -> print out their values/read them -> oh.

Not noticing that the code doesn’t run means being a bit out of touch with it. Gotta get in there.

:stuck_out_tongue:

Anyways @ionatan could close this topic to prevent more posts under this thread?