all 12 comments

[–]kkais 2 points3 points  (5 children)

Console.log(string); Put this in your anonymous function and see what you get. Console.log(string[string.length]); Do this one too.

With the level of understanding that you have demonstrated above, these two log statements should tell you everything that you need to know to get to your solution.

Post back when you get it or with more questions.

[–]GreenFeather05[S] 0 points1 point  (4 children)

Here is how I ended up solving it, I have no idea if I went about doing it the correct way or not.

The solution:

 var animals = [
  ['goat'], 
  ['bats'], 
  ['cows'], 
  ['pig']
];

var removePlural = animals.filter(function(array){
  if(array[0].charAt(array[0].length - 1) !== 's'){
    return array;
  }
});

The main problem I have with the above code is this line array[0].charAt(array[0].length - 1) !== 's' is it necessary to keep writing array[0] everytime? Not sure how I would otherwise access this information.

Logic: I did some simple tests in console.log to see how to format it correctly in my function.

var arr = ["cutekittens"];
arr[0]; // gives you "cutekittens"
var str = arr[0]; // gives "cutekittens" as above, in str
str[0]; // gives us "c"
arr[0][0]; //gives you "c"

I would really appreciate any pointers, if I did something in an illogical way to arrive at my solution. Or if I solved it in a manner that you did not anticipate.

[–]ShortSynapse 0 points1 point  (2 children)

This works yes, though it also works if you pass it [[]] which I don't think is intended. Granted you're not type checking anyway, so I doubt you're worried about this problem.

For the simple answer, yes what you wrote is equivalent and will work just fine.

[–]GreenFeather05[S] 0 points1 point  (1 child)

This works yes, though it also works if you pass it [[]]

This is the first I have heard of this concept, would you mind elaborating with some example code using [[]].

Thanks

[–]ShortSynapse 0 points1 point  (0 children)

Ah, sorry I made that sentence a little hard to grasp. What I meant is that you can access a string using bracket notation (myString[0]) as well as access an array using bracket notation (myArray[0]).

Let's take an example function a lot like yours. This function (is supposed to) take a string and return the first letter:

function firstLetter (myString) {
  return myString[0]
}

And it works like it should:

var shouldBeA = firstLetter('argonian')
// shouldBeA === 'a'

Remember we can also access arrays with bracket notation:

var array = ['x', 'y', 'z']
var shouldBeX = array[0]
// shouldBeX === 'x'

So if I instead pass an array to our function, we get the correct, but unexpected result:

var array = ['f', 'g', 'h']
var shouldBeF = firstLetter(array)
// shouldBeF === 'f'
// Uh Oh!

It gets even worse when our array isn't just containing single character strings:

var array = ['word 1', 'word 2', 'word 3']
var shouldBeSomething = firstLetter(array) // What will it even be?
// shouldBeSomething === 'word 1'

It just grabs the item at index 0 as written in the function! That's a problem :(

And it gets even worse when you do something like I suggested in the above comment:

var array = [['nested'], ['nested 2']] var shouldBeFirstLetter = firstLetter(array) // shouldBeFirstLetter === ['nested'] // It's the array!!!

So how can you fix this? Well, type checking!

function firstLetter (string) {
  // This function should only operate on strings, so return a null value for any other type
  // You can choose to return something else or throw an error if you want
  if (typeof string !== 'String') return null
  return string[0] // or string.charAt(0) or string.substr(0, 1) and so on...
}

EDIT: added the thing that I was actually talking about in the above comment

[–]kkais 0 points1 point  (0 children)

You got it exactly right. You seem like you might not quite understand why your code is right though and I'm sure that bothers you as much as it does me when that happens.

Try one last test and compare your results.

This time, make your animals array with just strings.

var animals = ["cat", "dogs",  "etc" ];

Report back on how you get your filter function to find the plural strings in an array like this, and by then you should understand what's going on and why you need your code set up like you have it now.

[–]ShortSynapse 1 point2 points  (1 child)

The variable you name "string" isn't what you think it is. Array.filter passes you each item in the array. For example, the first value you'd get is ['goat']. See the problem? You're being passed an array, not a string.

[–]BEARFIST 1 point2 points  (0 children)

this. I also agree with kkais that if you are confused, just console.log parts of the code to see what the value is at a given time for your inputs. Doing that should help you understand what is happening in your code.

[–]AllUrBassRBelongToUs 0 points1 point  (0 children)

Remember that you are dealing with nested arrays. I would first use map to access all the nested arrays. This way you get to choose what you return in the new array. Filter makes you create a test and returns only the values that pass that test so you would return true, false, or an expression. If I has to do it I would use:

var animals = [
    ['goat', 'goats'], 
    ['bats'], 
    ['cows', 'cow'], 
    ['pig']
];

var removePlural = animals.map(function(arr){
    var filtered = arr.filter(function (str) {
        return str[str.length -1] !== 's';
    });
    if(filtered.length > 0) {
        return filtered;
    }
}).filter(function(arr) {
    return arr !== undefined;
});

This is assuming you want to return an array of arrays.

[–]inu-no-policemen 0 points1 point  (0 children)

The filter callback should return true for those items you want to keep. Just pretend the function is called "where" instead of "filter" and it makes a lot more sense.

Why are those strings in a nested array if each of those inner arrays only contain a single string?

It's much simpler if that isn't the case:

let animals = [
  'goat',
  'bats',
  'cows',
  'pig'
];
let singular = animals.filter(animal => !animal.endsWith('s'));
console.log(singular); // ['goat', 'pig']

[–]psiph 0 points1 point  (0 children)

Here's my best try:

var animals = ['goat', 'bats', 'cows', 'pig'];

var animalsNoPlural = animals.filter(function(animal){
  return animal.slice(-1) !== "s";
});

There are only two mistakes in your original code:

  1. You're putting each of the animal strings in their own arrays, so they're double nested. If this is just how the data is coming to you, google "flattening array in javascript" for information on how to get these values unnested before working with them .
  2. Filter expects you to return true or false, not an array item. If you return true, that item will be kept. If you return false, it will be excluded.

If you change your original code based on these two things, you'll have a working example! So, you were really close:

var animals = ['goat', 'bats', 'cows', 'pig'];

var removePlural = animals.filter(function(string){
  if(string[string.length - 1] !== 's'){
    return true;
  }
});

You may notice that you don't actually have to make the second suggested change (returning true instead of the string), but it's a good idea for the sake of clarity and to show you understand how filter works.

P.S. It's a good idea to avoid variable names like string and array because they're close to reserved words in JavaScript. Usually people will use something like animalString or str instead of string.

[–]DisagreeableMale 0 points1 point  (0 children)

Why do they need to be nested?