Например, если я имел "scissors"
в переменной и хотел знать положение всех вхождений буквы "s"
, он должен распечатать 1, 4, 5, 8
Как я могу сделать это в JavaScript наиболее эффективным способом? Я не думаю, что цикл через все ужасно эффективен
Например, если я имел "scissors"
в переменной и хотел знать положение всех вхождений буквы "s"
, он должен распечатать 1, 4, 5, 8
Как я могу сделать это в JavaScript наиболее эффективным способом? Я не думаю, что цикл через все ужасно эффективен
Простой цикл работает хорошо:
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 является самым быстрым.
С помощью встроенного метода 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
!
Когда я сравнивал все, что казалось, что регулярные выражения выполняются лучше всего, поэтому я придумал этот
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]}
таким образом вы можете получить все индексы ваших совпадений за один раз
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. Добавьте +1 в i
, если нужно.
Более функциональное удовольствие, а также более общее: это находит начальные индексы подстроки любой длины в строке
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]
indices = (c, s) => s
.split('')
.reduce((a, e, i) => e === c ? a.concat(i) : a, []);
indices('?', 'a?g??'); // [1, 3, 4]
Вы также можете использовать функцию match() в javascript. Вы можете создать регулярное выражение и затем передать его в качестве параметра в match().
stringName.match(/s/g);
Это должно вернуть вам массив всех вхождений буквы 's'.
Мне понравился вопрос, и я решил написать свой ответ, используя метод 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