Credit Card Checker

< // 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:

function validateCred(){
for (let i = 15; i = 0; i–){
if (i % 2 === 0) {
[i] = [i] *2; {
if ([i] > 9){
[i] = [i] - 9
} else {
[i] = [i]
}
}
} else {
[i] = [i]
}

}

}

/>
The above is my code so far for the “Credit Card Checker” Project. https://www.codecademy.com/practice/projects/credit-card-checker

In the third step, it asks for me to set a function parameter of an array; can you set a function with an array parameter by function validateCred() {
}?

That parameter would be invalid since it is a literal object, much like writing a number or string, which would also be invalid as they are values.

If we say that a function takes an array, then the argument is where the array would be submitted…

validateCred([6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6])

function validate(cardArray) {

}

So I can place any placeholder value into the argument? such as “arr”… How am I going to get it to call all the arrays it needs to go through?

With one call to the function for each credit card.

Inside the function,

for (let i = 15; i >= 0; i--) {
    if (i % 2 === 0) {
        
    }
}

There’s no quicker way than to call the function 15 times?

If you have 15 credit card numbers, each represented an array, then it makes sense to evaluate one card at a time. That doesn’t preclude pre-loading an array with all the arrays you have lined up, and give that array to a controller function that makes the individual calls.

The key is to limit the task of the single card function to exactly what the controller function needs to see in return. Still haven’t viewed the actual project, so will go and do that now. tbc…


Something that jumps right out is the batch array (1). Still haven’t read the instructions or written any code but follows that the controller will iterate through the batch arrray and pass one at a time to the validator, possibly logging the outcomes on each trial so able to summarize at the end which cards are good, and which are not. tbc…



  1. The batch array contains references, not raw data. Each of the fifteen named arrays make up those references.

One of the key rules of this exercise is that the original array may not be mutated. This is an important hint. It suggests we don’t need a data structure in our solution. However, in the early build stages one will be useful for debugging and verifying our algorithm.

const doubles = []

This will be our temporary data structure to contain all the values that are doubled, and not doubled corresponding to the original array. We don’t want it to be a reference to the orginal so must build it brick by brick using only values.

for (let i = 15; i >= 0; i--) {
    let x = arr[i]
    if (i % 2 === 0) {
      x *= 2
      if (x > 9) {
        x -= 9;
      }
    }
    doubles.unshift(x)
  }
return doubles

When we compare doubles to the original array, we expect the values to mesh up with our expected result.

console.log(valid1)

console.log(validCred(valid1))

Once we can visually confirm that everything is up to muster, then we no longer need the data structure and can go about accumulating a sum of the values thus computed (or not, as the case may be) which sum is evaluated against mod 10. Divisible means true.

//const doubles = []
let sum = 0
...
    //doubles.unshift(x)
    sum += x

return sum % 10 === 0

What we have created is known as a, predicate function. The expected return value is a boolean. The above is a smart predicate because it was able to perform the algorithm internally and generate an outcome for evaluation, as opposed to just evaluating an input directly. Needless, the goal is the same. The input is treated as an assertion and the return is the answer to it.

console.log(valid1)

console.log(validCred(valid1))

The next step in the project is broken down into two parts. The first part is to find all the cards that are invalid. We can use the above predicate function as often as we wish. It does some of the heavy lifting so our controller function can be simplified to exihibit repetition as abstracted away.

const findInvalidCards = function (arr) {
  const invalid = []
  for (let x of arr) {
    if (! validCred(x)) {
      invalid.push(x)
    }
  }
  return invalid
}
console.log(findInvalidCards(batch))

If we examine the above function we see that it is filtering data from in input data set. Only invalid cards are in the return array. Wouldn’t you know it, ES has a built in iterator for that purpose.

const findInvalidCards = function (arr) {
  /*
  const invalid = []
  for (let x of arr) {
    if (! validCred(x)) {
      invalid.push(x)
    }
  }
  return invalid
  */
  return arr.filter(x => ! validCred(x))
}

which gets further abstracted to,

const findInvalidCards = arr => arr.filter(x => ! validCred(x));
1 Like

// 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:

function validateCred(arr){
for (let i = 15; i >= 0; i–){
if (i % 2 === 0) {
arr[i] = arr[i] *2;{
if (arr[i] > 9){
arr[i] = arr[i] - 9
} else {
arr[i] = arr[i]
}
}
} else {
arr[i] = arr[i];
}
}

let sum = 0;
for (let i = 0; i < arr.length; i++){
sum += arr[i];
}
if (sum % 10 === 0 ){
return true;
} else {
return false;
}
}

console.log(validateCred(valid1));

let batch2 = ;

function findInvalidCards(batch){
for (let i = 0; i < batch.length; i++){
return validateCred(arr);
if (return === false){
batch2.push(batch[i]);
}

}
}

Here is my new code. It runs up until let batch2 = ; …

The instructions are " Create another function, findInvalidCards() that has one parameter for a nested array of credit card numbers. The role of findInvalidCards() is to check through the nested array for which numbers are invalid, and return another nested array of invalid cards."

I’m not sure how to pull the value from the previous code into my new code which will run through the nested array batch

This is mutating the original array. We must not do that, according to the instructions.

This is touched on in an earlier post.

let x = arr[i]

Let’s go over that algorithm.

But with scoping, wouldn’t the original argument remain unchanged?

Data structures are passed by reference. Within the function the bindings are still the same. Even inside the function, valid1 by any local name still refers to valid1.

Note that when we assign an element value to a variable, the value is assigned, not a reference. Any change we make to that value will not affect the array we are taking it from.

A things of misunderstanding here:

  1. What is being scoped.
  2. Argument and parameters.
  3. How arguments are passed into functions.
  4. reference Vs value types

Your assumption about the argument being scoped to the local function is actually kind of true, but let’s make your understanding clear.

An argument is what is passed into a function when it is being used. A parameter is the variable that passed in arguments are assigned to. They are talking about the same things really but it depends which side of the fence you are on. If I said you are missing an arguement then I’d be talking about how you used the function and if I say you are missing a parameter then I am talking about how you wrote the function.

// This function expects two parameters.
function funcA(paramA, paramB){
    return paramA + paramB
}

// Here we pass in two arguments.
funcA(1, 5)

Anyway, why the slight pedantic point? The parameter variable is what gets scoped not the argument, it cannot be directly accessed outside the function.

Now how are arguments passed into functions? The value is copied (this is known as being passed by value), so you were right the value that the parameter see is not the same value as the argument passed into the function. So why is it that changes make to the array is reflected to the original array that is passed in?

Because an array is a reference type and isn’t directly stored in a variable, what is stored is a reference (something that points to the memory space that actually stored the array). When using a variable that stores the reference once the black magic behind the scenes has done its work it is like using the array directly.

References are light weight and cheap to copy, so when you pass a reference type into a function the reference gets copied and a new reference is made. So you have two references but they both point to the same array, meaning that when you make a change with the new reference in the function the changes happen to the centrally stored array meaning all other references looking at that array will see the change too.

One thing that people get confused about is thing reference type get passed by reference, they do not they still get passed by value, it is just that the value is a reference… Yeah, a lot of references there, hence the confusion.

What would passing by reference be? Well let’s start by saying in JavaScript you cannot pass by reference so this doesn’t matter unless you move to a language that can. Passing by reference gives you direct access to the original variable that is passed in, allowing you to change the original variable’s value directly.

This is what it would look like/happen if you could do it in JavaScript. This obviously won’t really work.

// Lets pretend varByRef is passed by reference with a pretend ref keyword
let passRef = ref varByRef => {varByRef = [3, 4]}

let a = [1,  2]

passRef(a)
// a would now equal [3, 4]

See how even though we don’t reassign a it changes to now reference the new array assigned in the function. That is passing by reference at a basic level.

1 Like