-2

I am creating a function that:

  • returns an array containing all the odd length word elements of the array located at the given key.
  • If the array is empty, it should return an empty array.
  • If it contains no odd length elements, it should return an empty array.
  • If the property at the given key is not an array, it should return an empty array.
  • If there is no property at the given key, it should return an empty array.

Here's my solution which works on some part so far:

function getOddLengthWordsAtProperty(obj, key) {

  var output = [];

  for(var i = 0; i < obj.key.length; i++){
     if (key in obj){
       if (Array.isArray(obj[key])){
         if(obj[key].length){
         if(obj.key[i].split("").length % 2 !== 0){
            output.push(obj.key[i]);
         }   

   }
   }

  }else{
    return [];
  }

 }

  return output;
}



var obj = {
  key: ['It', 'has', 'some', 'words']
};

var output = getOddLengthWordsAtProperty(obj, 'key');
console.log(output); // --> ['has', 'words']

The problem here is that my codes return:

TypeError: Cannot read property 'length' of undefined

Soviut
  • 88,194
  • 49
  • 192
  • 260
  • you should first check if `key` is present or not then use the for loop – warl0ck Jun 20 '17 at 03:56
  • Should your for loop code be obj[key].length? – H77 Jun 20 '17 at 03:56
  • That's some confusing naming you've got there. So `key` is a property of `obj` AND an index of obj? I don't think `Array` even has a property called `key`. – Clonkex Jun 20 '17 at 04:10
  • 1
    You can't use `obj.key[i]` like this, you still have to use `obj[key][i]` - if this is working, it's probably because you called your first key 'key' in your example. If you want to access an object's properties with a variable name, you have to use the bracketed notation. – Brett East Jun 20 '17 at 04:43

3 Answers3

4

All you need to use is filter...

Use % 2 and if it's odd it will be 1 which is truthy and will return the correct array.

function getOddLengthWordsAtProperty(obj, key) {
  if ( key in obj && Array.isArray(obj[key]) )
  {
      return obj[key].filter( (item) => item.length % 2 );
  }
  
  return []; // don't need else as return would end the function if it went into 'if'
  
}

var obj = {
  key: ['It', 'has', 'some', 'words']
};

var output = getOddLengthWordsAtProperty(obj, 'key');
console.log(output); // --> ['has', 'words']
A. L
  • 11,695
  • 23
  • 85
  • 163
  • Bear in mind ES6 arrow functions can be super confusing for beginners. And me. – Clonkex Jun 20 '17 at 04:11
  • arrow functions are (simply put) shorter versions of functions. You should learn it because it has its useful properties. If you understand functions, there's no reason why arrow functions are 'super confusing'. They might seem weird at the start, but they're not even that complex if you understand what a function does. – A. L Jun 20 '17 at 04:12
  • 2
    Using `.filter()` is a good plan, but your function doesn't cover the OP's last two requirements (the specified property may not exist or may not be an array). – nnnnnn Jun 20 '17 at 04:24
  • Well what arrow functions _do_ isn't confusing (although as I'm sure you're aware they do [behave differently](https://stackoverflow.com/questions/34361379/arrow-function-vs-function-declaration-expressions-are-they-equivalent-exch) to normal functions), but the _syntax_ is confusing as it's completely unique to JavaScript (afaik) and is very un-C-like. The arrangement of symbols doesn't line up with any other language's function definition, so instead of being intuitive and immediately obvious, it takes thought and time to work out what's going on. – Clonkex Jun 20 '17 at 04:51
  • @Clonkex I feel like you're just refusing to understand it. If I wrote `(value) => { return value }` you'll probably be more accepting – A. L Jun 20 '17 at 04:55
  • I do understand it. I never said I didn't. But I still find arrow functions confusing. When I am skimming source code I find that I have to stop and carefully read through the arrow functions to work out what's going on. It just seems like there's an excessive amount of symbols with not enough keywords to make them easy to read. Most people seem to love them, but I doubt I ever will. – Clonkex Jun 20 '17 at 04:58
  • Incidentally, including the curly braces does definitely make the function easier to comprehend. – Clonkex Jun 20 '17 at 04:59
  • I think the problem I have with them is that they look like an expression, not a definition. There's lots of symbols but no keywords, so it always looks like you're doing some weird expression in place of a function. It also isn't self-explanatory (not that coding is exactly self-explanatory anyway, but it usually uses English so you can work it out). What does the arrow mean? Putting this variable into a scope? And why is the value in brackets? It just... doesn't make sense to me. I understand how they work but are so very awkward. I'm sure I can't be the only one to feel this way. – Clonkex Jun 20 '17 at 05:34
  • @Clonkex yeah, but that's like saying it's confusing to use `||` and `&&` instead of python's `or` `and` since they're just symbols – A. L Jun 20 '17 at 05:35
1

I see two issues with this function.

First, obj.key is the same as obj["key"]. You want to use obj[key] instead.

Second, you should put the validations like if (key in obj) outside of your loop. That way you can safely reference obj[key].length in your loop declaration without worrying about getting that error.

1

You should first check if key property is even present or not before using the for loop this gives you the above error when there is no key property present

Below is the snippet that should work without any errors.

function getOddLengthWordsAtProperty(obj, key) {

  var output = [];

  if (key in obj && Array.isArray(obj[key])) {
    var len = obj.key.length;
    for (var i = 0; i < len; i++) {
      if (obj.key[i].length % 2 !== 0) {
        output.push(obj.key[i]);
      }
    }
  }
  return output;
}

var obj = {
  key: ['It', 'has', 'some', 'words']
};

var output = getOddLengthWordsAtProperty(obj, 'key');
console.log(output);
warl0ck
  • 3,356
  • 4
  • 27
  • 57
  • Correct, but you could further simplify it by removing the `else` and moving `return output` to after the `if` block. Also, `if(key in obj && Array.isArray(obj[key]))` could be cut down to `if(Array.isArray(obj[key]))`. – nnnnnn Jun 20 '17 at 04:22
  • Thanks for the input, but if I only check `if(Array.isArray(obj[key]))` wouldn't it give error if there is no `key` property of the object. I have updated the answer to return only once. – warl0ck Jun 20 '17 at 05:03
  • There's certainly no *need* to change the if condition, so I wouldn't change that in the answer - I was just commenting for those who like shorter code. But anyway it would work because if the property doesn't exist then `obj[key]` doesn't give an error, it evaluates as `undefined`, and `Array.isArray(undefined)` returns `false`. – nnnnnn Jun 20 '17 at 09:57