Home > Software design >  Unable to return index with filter method JS
Unable to return index with filter method JS

Time:09-17

enter image description hereI'm trying to return the index of an element in an array if it is a vowel, I'm unsure as to why I am unable to return the index with my code as it stands, the mdn states that the filter method should be able to return the element, elements index, or the name of the array so I'm a bit confused as to why I'm not able to do what I want, would someone be able to help me or at least break down why I can't do this?

here is my code below as well as a screenshot of what is being returned. I appreciate the help in advance

function vowelIndices(word) {
    let result = word.split('').filter((element, index) => {
        if (element.toLowerCase() === 'a' ||
            element.toLowerCase() === 'e' ||
            element.toLowerCase() === 'i' ||
            element.toLowerCase() === 'o' ||
            element.toLowerCase() === 'u' ||
            element.toLowerCase() === 'y') { return index   1 }
    })
    console.log(result)
    return result
}
vowelIndices("apple")

CodePudding user response:

filter works differently , in each iteration of filter function you can return one boolean if its true it will be stored and ignored if you return false lets see an example

let arr = ["apple" , "mango" , "banana" , "pinapple" , "orange"]
let res = arr.filter(each=>{
    if(each == "apple" || each == "mango" || each == "orange"){
        return true
    }
    else {return false}
})
console.log(res) // output [ 'apple', 'mango', 'orange' ]

now to find vowels you can use foreach or reduce reduce is a bit difficult to understand at first

let test = `I'm trying to return the index of an element in an array if it is a vowel, I'm unsure as to why I am unable to return the index with my code as it stands, the mdn states that the filter method should be able to return the element, elements index, or the name of the array so I'm a bit confused as to why I'm not able to do what I want, would someone be able to help me or at least break down why I can't do this?`

// with foreach function
function findVowel(str){
    let res = []
    str.split("").forEach((each,i)=>{
        if(each.match(/[aeiou]/i)){res.push(i)}
    })   
    return res 
}

// with reduce function
function findVowel2(str){
    return str.split("").reduce((acc,each,index)=>{
        if(each.match(/[aeiou]/i)){acc.push(index)}
        return acc
    },[])
}

console.log(findVowel(test))
console.log(findVowel2(test))

CodePudding user response:

In the example, the function locateChars(text, ...terms) can return indexes of matches for any type of string and/or array of strings.

Details are commented in example

const data = "here is my code below as well as a screenshot of what is being returned. I appreciate the help in advance";

/**
 * Given an array of strings or a string, and one
 * or more strings to match against, return an array
 * of indexes. The indexes should correspond to
 * matches.
 * @param {array/string} text - An array of strings
 *        or a string.
 * @param {string<rest>} ...terms - A rest parameter
 *        of one or more strings to find matches of
 * @return {array<number>} - An array of index numbers
 *         that corresponds to matches
 */
function locateChars(text, ...terms) {
  /**
   * If >text< is an array, .join() it into a string
   * >chars< is >text< string converted into an array 
   * of chars.
   */
  let chars = Array.isArray(text) ? [...text.join('')] : [...text];
  // Convert any uppercase chars to lowercase
  chars = chars.map(c => c.toLowerCase());
  /**
   * Compare the contents of >...terms< with each
   * char of >chars< and return only the index number
   * if there's a match
   */
  return chars.flatMap((chr, idx) => [...terms].includes(chr) ? idx : []);
}

console.log(locateChars(data, "a", "e", "i", "u", "y"));

CodePudding user response:

Array.filter can only include or exclude elements from the result–it cannot change them in any way. This is documented on the MDN page.

If you want to get the indices of elements that have some property, you must convert the array to a form that pairs indexes with elements. Array.map will do this, as will Array.entries. The difference in this case is than the result of map is an array, while entries is an iterator. The latter doesn't have a filter method, so you'd need to convert it to an Array with (e.g.) Array.from or by spreading.

word.split('').map((ch, i) => [i, ch])
// or
Array.from(word.split('').entries())
// or
[...word.split('').entries()]

At that point, you can use filter to select just the vowels, then map again to discard the characters, keeping just the indices.

Note that the vowel test is inefficient an inelegant. A better way would be to use a set, either a Set instance or an object literal with the set elements as keys. For example:

const vowels = new Set('aeiouyAEIOUY');
...
    .filter(([i, ch]) => Set.has(ch))

Alternate Solution: Regex

This is a case that a regex can handle quite well, given the minimal amount of context and simple character sequence to match (a single letter). It can even distinguish 'y' at the end of a word, which is the only position it should be considered a vowel. [String.matchAll][6], with the right regex, can find all vowels. As with Array.entries, it returns an iterator, which will need to be spread so map can discard all but the indices from the matches.

[...word.matchAll(/[aeiou]|y\b/g)].map(m => m.index);

This also has the advantage of working not only on a single word, but any string of multiple words.

  • Related