76

例如,如果我有"scissors"一个变量并且想知道所有字母出现的位置"s",它应该打印出来1, 4, 5, 8

如何以最有效的方式在 JavaScript 中执行此操作?我不认为循环遍历整个过程非常有效

4

13 回答 13

109

一个简单的循环效果很好:

var str = "scissors";
var indices = [];
for(var i=0; i<str.length;i++) {
    if (str[i] === "s") indices.push(i);
}

现在,您表示需要 1、4、5、8。这将为您提供 0、3、4、7,因为索引是从零开始的。所以你可以添加一个:

if (str[i] === "s") indices.push(i+1);

现在它会给你你预期的结果。

小提琴可以在这里看到。

我不认为循环遍历整个过程非常有效

就性能而言,我认为在您开始遇到问题之前,您无需担心这一点。

这是一个比较各种答案的jsPerf测试。在 Safari 5.1 中,IndexOf 表现最好。在 Chrome 19 中,for 循环是最快的。

在此处输入图像描述

于 2012-05-22T21:24:05.673 回答
31

使用本机String.prototype.indexOf方法最有效地找到每个偏移量。

function locations(substring,string){
  var a=[],i=-1;
  while((i=string.indexOf(substring,i+1)) >= 0) a.push(i);
  return a;
}

console.log(locations("s","scissors"));
//-> [0, 3, 4, 7]

然而,这是一个微优化。对于一个足够快的简单而简洁的循环:

// Produces the indices in reverse order; throw on a .reverse() if you want
for (var a=[],i=str.length;i--;) if (str[i]=="s") a.push(i);    

事实上,原生循环在 chrome 上比使用indexOf!

来自链接的性能结果图

于 2012-05-22T21:24:20.470 回答
13

基准

当我对所有东西进行基准测试时,似乎正则表达式表现最好,所以我想出了这个

function indexesOf(string, regex) {
    var match,
        indexes = {};

    regex = new RegExp(regex);

    while (match = regex.exec(string)) {
        if (!indexes[match[0]]) indexes[match[0]] = [];
        indexes[match[0]].push(match.index);
    }

    return indexes;
}

你可以这样做

indexesOf('ssssss', /s/g);

这将返回

{s: [0,1,2,3,4,5]}

我需要一种非常快速的方法来匹配多个字符与大量文本,例如你可以这样做

indexesOf('dddddssssss', /s|d/g);

你会得到这个

{d:[0,1,2,3,4], s:[5,6,7,8,9,10]}

这样您就可以一次性获取所有匹配项的索引

于 2014-08-01T16:30:51.707 回答
11
function charPos(str, char) {
  return str
         .split("")
         .map(function (c, i) { if (c == char) return i; })
         .filter(function (v) { return v >= 0; });
}

charPos("scissors", "s");  // [0, 3, 4, 7]

请注意,JavaScript 从 0 开始计数i。如果必须,请将 +1 添加到 。

于 2012-05-22T21:26:43.323 回答
7

功能更有趣,也更通用:这会找到字符串中任意长度的子字符串的起始索引

const length = (x) => x.length
const sum = (a, b) => a+b

const indexesOf = (substr) => ({
  in: (str) => (
    str
    .split(substr)
    .slice(0, -1)
    .map(length)
    .map((_, i, lengths) => (
      lengths
      .slice(0, i+1)
      .reduce(sum, i*substr.length)
    ))
  )  
});

console.log(indexesOf('s').in('scissors')); // [0,3,4,7]

console.log(indexesOf('and').in('a and b and c')); // [2,8]

于 2016-10-27T09:59:13.577 回答
4

在现代浏览器中 matchAll完成这项工作:

const string = "scissors";
const matches = [...string.matchAll(/s/g)];

您可以通过多种方式获取值。例如 :

const indexes = matches.map(match => match.index);
于 2021-12-12T09:32:51.293 回答
4
indices = (c, s) => s
          .split('')
          .reduce((a, e, i) => e === c ? a.concat(i) : a, []);

indices('?', 'a?g??'); // [1, 3, 4]
于 2017-11-08T00:21:20.040 回答
1

使用 while 循环

let indices = [];
let array = "scissors".split('');
let element = 's';
    
let idx = array.indexOf(element);
    
while (idx !== -1) {
   indices.push(idx+1);
   idx = array.indexOf(element, idx + 1);
}
console.log(indices);

于 2020-08-07T17:26:08.387 回答
1

另一种选择可能是使用flatMap.

var getIndices = (s, t) => {
  return [...s].flatMap((char, i) => (char === t ? i + 1 : []));
};

console.log(getIndices('scissors', 's'));
console.log(getIndices('kaios', '0'));

于 2021-03-20T07:43:41.867 回答
1

这是使用函数表达式(使用 ES6 箭头函数)的简短解决方案。该函数接受一个字符串和要查找的字符作为参数。它将字符串拆分为一个字符数组,并使用一个reduce函数来累积并将匹配的索引作为数组返回。

const findIndices = (str, char) =>
  str.split('').reduce((indices, letter, index) => {
    letter === char && indices.push(index);
    return indices;
  }, [])

测试:

findIndices("Hello There!", "e");
// → [1, 8, 10]

findIndices("Looking for new letters!", "o");
// → [1, 2, 9]

这是一个紧凑的(单行)版本:

const findIndices = (str, char) => str.split('').reduce( (indices, letter, index) => { letter === char && indices.push(index); return indices }, [] );
于 2020-04-28T01:50:01.233 回答
0

我喜欢这个问题,并想用reduce()数组上定义的方法来写我的答案。

function getIndices(text, delimiter='.') {
    let indices = [];
    let combined;

    text.split(delimiter)
        .slice(0, -1)
        .reduce((a, b) => { 
            if(a == '') {
                combined = a + b;
            } else { 
                combined = a + delimiter + b;
            } 

            indices.push(combined.length);
            return combined; // Uncommenting this will lead to syntactical errors
        }, '');

    return indices;
}


let indices = getIndices(`Ab+Cd+Pk+Djb+Nice+One`, '+');
let indices2 = getIndices(`Program.can.be.done.in.2.ways`); // Here default delimiter will be taken as `.`

console.log(indices);  // [ 2, 5, 8, 12, 17 ]
console.log(indices2); // [ 7, 11, 14, 19, 22, 24 ]

// To get output as expected (comma separated)
console.log(`${indices}`);  // 2,5,8,12,17
console.log(`${indices2}`); // 7,11,14,19,22,24
于 2019-01-15T14:48:46.207 回答
0

只是为了进一步的解决方案,这是我的解决方案:您可以找到字符串中存在的字符索引:

findIndex(str, char) {
    const strLength = str.length;
    const indexes = [];
    let newStr = str;

    while (newStr && newStr.indexOf(char) > -1) {
      indexes.push(newStr.indexOf(char) + strLength- newStr.length);
      newStr = newStr.substring(newStr.indexOf(char) + 1);
    }

    return indexes;
  }

findIndex('scissors', 's'); // [0, 3, 4, 7]
findIndex('Find "s" in this sentence', 's'); // [6, 15, 17]

于 2020-04-12T18:27:01.080 回答
-1

您也可以使用 javascript 的 match() 函数。您可以创建一个正则表达式,然后将其作为参数传递给 match()。

stringName.match(/s/g);

这应该会返回一个包含所有出现的字母“s”的数组。

于 2018-04-21T05:16:42.940 回答