【问题标题】:Unable to return index with filter method JS无法使用过滤方法JS返回索引
【发布时间】:2022-09-25 10:23:57
【问题描述】:

我试图返回数组中元素的索引,如果它是元音,我不确定为什么我无法用我的代码返回索引,mdn 声明过滤方法应该能够返回元素、元素索引或数组的名称,所以我有点困惑为什么我不能做我想做的事,有人能帮助我或至少打破为什么我不能这样做?

这是我下面的代码以及返回内容的屏幕截图。我提前感谢您的帮助

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\")
  • 那不是过滤器方法的用途。 Filter 返回一个新数组,其中包含回调函数为其返回真值的所有元素。使用findIndex() 获取匹配条件的元素的索引。
  • 在这种情况下,屏幕截图没有传达任何有用的信息。您想提供一个minimal reproducible example(谢谢),这就是代码所需的全部。 Images 应该用于说明视觉问题或要求,例如布局问题。
  • MDN 声明回调传递给String.filter收到元素、索引和数组,而不是它可以返回其中任何一个。它谈到了回调的返回值:\“返回一个强制为 true 以保留元素的值,否则为 false。\”
  • 为什么指数会增加?
  • 这个是来做什么的?

标签: javascript arrays indexing filter


【解决方案1】:

过滤器的工作方式不同,在过滤器函数的每次迭代中,您可以返回一个布尔值,如果它为真,它将被存储并在您返回假时被忽略 让我们看一个例子

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' ]

现在找到可以使用 foreach 或 reduce 的元音reduce 一开始有点难理解

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))

【讨论】:

    【解决方案2】:

    在示例中,函数locateChars(text, ...terms) 可以返回任何类型的字符串和/或字符串数​​组的匹配索引。

    细节在例子中注释

    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"));

    【讨论】:

    • 为什么映射toLowerCase?为什么不在调用flatMap 之前将其链接起来?
    • 这是完全可行的,但我将这一步分开放置,因为尝试用一系列方法评论单行变得很困难。
    • 您始终可以将每个链接调用放在单独的行上,并在它们之间穿插 cmets。更好的是完全删除map 并调用toLowerCase,然后再将字符串传播到一个数组中。您还可以将价差移到三元之外,而不是重复:[...(Array.isArray(text) ? text.join('') : text).toLowerCase()]
    • Thar 很漂亮,但对于新手来说可能太多了。
    • 我认为它与当前方法一样清晰,并且不使用map 更简单。如果您想将其分解为清楚起见,您可以将字符串转换(即三元表达式)、小写转换和数组转换分开。 [...terms] 是另一个不必要的复杂性(特别是因为它是针对chars 中的每个字符执行的)terms 已经是一个数组,所以你可以简单地调用terms.includes。但是,那是O(terms.length);最好还是使用一套。
    【解决方案3】:

    Array.filter 只能在结果中包含或排除元素——它不能以任何方式改变它们。这记录在 MDN 页面上。

    如果要获取具有某些属性的元素的索引,则必须将数组转换为将索引与元素配对的形式。 Array.map 会这样做,Array.entries 也会这样做。这种情况下的区别在于map 的结果是一个数组,而entries 是一个迭代器。后者没有filter 方法,因此您需要使用(例如)Array.fromspreading 将其转换为数组。

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

    此时,您可以使用filter 仅选择元音条目,然后再次使用map 丢弃字符,仅保留索引。

    请注意,元音测试效率低下。更好的方法是使用集合,Set 实例或以集合元素作为键的对象字面量。例如:

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

    替代解决方案:正则表达式

    这是一个正则表达式可以很好地处理的情况,给定最少数量的上下文和要匹配的简单字符序列(单个字母)。它甚至可以区分单词末尾的“y”,这是它应该被视为元音的唯一位置。 String.matchAll,使用正确的正则表达式,可以找到所有元音。与Array.entries 一样,它返回一个迭代器,需要将其展开以便map 可以丢弃匹配项中除索引之外的所有内容。

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

    这还具有不仅可以处理单个单词,还可以处理多个单词的任何字符串的优点。

    【讨论】:

      猜你喜欢
      • 2014-12-15
      • 1970-01-01
      • 1970-01-01
      • 2021-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多