Credit Card Checker Step 5 - How to target the first element of (inner) arrays?

Hi,

I encounter a problem with step 5 of the project.

Instructions: After finding all the invalid credit card numbers, it’s also necessary to identify the credit card companies that have possibly issued these faulty numbers. Create a function, idInvalidCardCompanies() that has one parameter for a nested array of invalid numbers and returns an array of companies.

To explain my code below: I went with a nested for loop, which I realise now was probably the best bet in terms of simplicity, and my method to make sure that the ‘faulty’ company name only appears once in the returned array is different than what the hint suggests: for some reason I found it more logical to create counter variables for each company, and when their values returned truthy it would add the name of that company to the array.

Now, the program technically “works”, as in it doesn’t throw any error or weird behaviour, but I’m having troubles making it do part of the job correctly: iterating through the first element of each inner array only, instead of all the elements. Or at least, targeting the first element only.

Currently, it checks if the numbers 3, 4, 5 or 6 are in each array regardless of the index, which results in the returned array being bound to be wrong if we were to work with different arrays (as in this project, all the companies are ‘faulty’ since all the invalid cards arrays start with either one of the 4 digits - so my result only looks correct, but if you were to remove all the arrays starting with 3 for instance, it would still include Amex in the returned array… because the loop checks the full array of invalid numbers, where 3 appears again multiple times).

This is my code (for step 5 only) with some comments and console.log to explain what happens:

const idInvalidCardCompanies = invalidCardsArray => {
  let invalidCompanies = [];
  let amexCounter = 0;
  let visaCounter = 0;
  let mastercardCounter = 0;
  let discoverCounter = 0;

  for (let i = 0; i < invalidCardsArray.length; i++) //iterates through each nested array 
  {
    for (let j = 0; j < invalidCardsArray[i].length; j++) //iterates through the elements of the inner arrays
    {
      //console.log(invalidCardsArray[i][0]); outputs all the first numbers of each inner array, 15-16 times each
     
      if (invalidCardsArray[i][j] === 3) {
        amexCounter++;
      }
      if (invalidCardsArray[i][j] === 4) {
        visaCounter++;
      }
      if (invalidCardsArray[i][j] === 5) {
        mastercardCounter++;
      }
      if (invalidCardsArray[i][j] === 6) {
        discoverCounter++;
      } 
    }
  }
  //console.log(amexCounter); // outputs 14
  //console.log(visaCounter); // outputs 12
  //console.log(mastercardCounter); // outputs 12
  //console.log(discoverCounter); // outputs 10

  amexCounter ? invalidCompanies.unshift('Amex') : console.log("Company not found");
  visaCounter ? invalidCompanies.unshift('Visa') : console.log("Company not found");
  mastercardCounter ? invalidCompanies.unshift('Mastercard') : console.log("Company not found");
  discoverCounter ? invalidCompanies.unshift('Discover') : console.log("Company not found");

  console.log ('These companies mailed out cards with invalid numbers: ' + invalidCompanies.join());
}

idInvalidCardCompanies(findInvalidCards(batch)); // Returns the array containing the 4 companies

So what I would need help with is: how do I make the loop iterate over the first element of each ‘inner’ array only, and all of them? Or, if that’s not possible, how do I target the first element in the if statement?

I don’t understand that when I do console.log(invalidCardsArray[i][0]); then only the first elements are logged, but when I try to write it as such in the if statement (like so: if (invalidCardsArray[i][0] === 3) and so forth) it just makes the counter variables increase respectively to 30/32/32/35…
I also tried writing it if (invalidCardsArray[i][j][0] === 3) but then the function logs 4 times ‘Company not found’ and an empty array. Feels like I’m grabbing at straws here.

I don’t know if it’s a syntax issue or a bigger problem. I also can’t find a method that would targets only the first element for this purpose and yet I feel like it’s right under my nose.

I know my solution is probably a bit too complicated, and I’ll probably start over again with a different approach, but if there is any way to make the above work, I would really like to know :slight_smile: my hours of Googling didn’t help me so far.

Many thanks to any charitable soul!

EDIT: Ugh, I also just realised that something was not quite right in my function: I wasn’t using the parameter I created nor was I passing an argument to it (pretty big oversight). Corrected that now, it still works and my question remains the same, but what do you know, in the process of correcting that mistake I think I just created my first higher order function!

There’s nothing to it other than lookup by index.
If you have an array of cards, then to get a card you’d look it up by its index.
If you have a card you would get the first element by looking at index 0.

I understand that, it’s actually what I was attempting in my code with the [i][j][0] etc, but I must do something wrong because it’s not working. I’m confused as to which syntax to use inside the loop.

Thanks for your reply by the way!

If the first lookup is the array of cards, and the second is on a card, then what’s the third?

You’d choose what to write based on what you have, what you need, and what operation bridges that gap. Maybe the problem is not looking at what you have? You could print it out.

You’re making a guess, writing it, and then running it and seeing that the result is wrong.

You’re probably not going to get that right by trying different things and then looking at the final result.

Look at what you have after each operation instead.

Anyway, if you’re able to see each such value, then you are already successfully looking them up.

Right? There’s no problem looking up those values. Maybe the problem is about what should be done with the value after having obtained it.
Maybe you’d process each value immediately after obtaining it, or maybe you would put them all in an array and deal with them after having extracted them from the bigger data structure.

1 Like

Hey, sorry for my late-ish reply, I think I needed to let it rest for a day or two!

As you said, invalidCardsArray[i][0] does return the first element of the inner arrays, which is why I didn’t (and still don’t really) understand why my condition if (invalidCardsArray[i][0] === 3 ) kept on adding all the 3’s found in an array instead of adding it just once if 3 is the first element.

But, anyway, I took your advice of putting all the first values in a separate array instead and also made us of the indexOf() method. Turns out the code is a lot shorter, though I could probably have used something shorter than a nested for loop, but I’m just happy that it works fine now!

const idInvalidCardCompanies = invalidCardsArray => {
  let invalidCompanies = [];
  let firstDigits = [];
  for (let i = 0; i < invalidCardsArray.length; i++) //iterates through each nested array 
  {
    for (let j = 0; j < invalidCardsArray[i].length; j++) //iterates through the elements of the inner arrays
    {   firstDigits.unshift(invalidCardsArray[i][0]); }
  }
  
    if (firstDigits.indexOf(3) === -1) {
      console.log("Company not found")
    } else if (firstDigits.indexOf(3) !== -1 && invalidCompanies.indexOf('Amex') === -1) {
      invalidCompanies.unshift('Amex');
    }
    if (firstDigits.indexOf(4) === -1) {
      console.log("Company not found")
    } else if (firstDigits.indexOf(4) !== -1 && invalidCompanies.indexOf('Visa') === -1) {
      invalidCompanies.unshift('Visa');
    }
    if (firstDigits.indexOf(5) === -1) {
      console.log("Company not found")
    } else if (firstDigits.indexOf(5) !== -1 && invalidCompanies.indexOf('Mastercard') === -1) {
      invalidCompanies.unshift('Mastercard');
    }
    if (firstDigits.indexOf(6) === -1) {
      console.log("Company not found")
    } else if (firstDigits.indexOf(6) !== -1 && invalidCompanies.indexOf('Discovery') === -1) {
      invalidCompanies.unshift('Discovery');
    }

  console.log ('These companies mailed out cards with invalid numbers: ' + invalidCompanies.join());
}

idInvalidCardCompanies(findInvalidCards(batch));

Thanks a lot again for all your input!

that doesn’t modify an array. You’d need a different operation for that, likely array.push
so what you’re doing there is grouping together many operations and saying the whole thing isn’t behaving right.
look at the individual operations. break it apart as needed, find the ONE thing that isn’t doing what you meant, not a group. if it’s a group of things then you can narrow it down further.

The first thing you’d check is whether invalidCardsArray and i are the values you expect, and whether that expression is indeed 3, then you would check whether the comparison evaluates to true, then you would check if the if-clause does indeed execute as a result, or whether it instead skipped to the optional else-clause or otherwise after the if-statement if there’s no else. in fact, you might not want to have any other code there while you’re inspecting something.
presumably your iteration would then stop, if you have other code that shouldn’t run then maybe you would want to add prints in them to see that they are indeed not running
and then you could check whether the state at the start of the iteration and the end of the iteration do indeed have a difference between them that you would expect after one iteration
… and so on.

You don’t need to observe EVERYTHING but you do need to observe the things you do rely on. You’d start by making an observation roughly in the middle to determine whether things are okay at that point or not, and then look earlier or later, repeatedly cutting down your search space in half until you’re looking at just a single operation. When you’ve narrowed something down enough it becomes reasonable to look at EVERY aspect of it.

Likely, it has more to do with your expectation on how closely you should need to look than your ability to look. Your expectation should be that you control every single detail, and as such, you would also look at every single detail.

If you say posted some code and described how it behaves incorrectly, the only reason I would be able to reliably spot the problem is my willingness to get in there and observe and compare to what should happen.
It’s got very little to do with being able to just stare it down and spot a problem.
Then it’ll turn out to be some trivial uninteresting mistake you already knew all about. Which is why I’m always telling people to go look instead of what I find, unless I am convinced that it can’t reasonably be found if looked at, in which case it should still be looked at to identify what the mystery is.

Hi there.

This is the way I did it. I tested it and and it appears to work but to be honest I’m not 100% sure. What would you say?

PD: I’m a begginner.

function idInvalidCardCompanies(invCardArr) {

let companies = ;

let cards = invCardArr.map((item) => {

if (validateCred(item) === false) {

  if (item[0] === 3) {

    companies.push('amex');

  } else if (item[0] === 4) {

    companies.push('visa');

  } else if (item[0] === 5) {

    companies.push('mastercard');

  } else if (item[0] === 6) {

    companies.push('discover');

  } else {

    companies.push(`card with number ${item} belongs to an unknown company`);

}

}

});

compNoDupli = companies.filter((item, pos) => {

return companies.indexOf(item) == pos;

});

return compNoDupli;

};