たとえば"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が得られます。したがって、1つ追加できます。
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);
実際、ネイティブループは、indexOf
!を使用するよりもChromeで高速です。
すべてをベンチマークしたとき、正規表現が最高のパフォーマンスを発揮したように見えたので、これを思いつきました
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からカウントされることに注意してくださいi
。必要に応じて、に+1を追加してください。
より機能的な楽しみ、そしてより一般的:これは文字列内の任意の長さの部分文字列の開始インデックスを検索します
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]
最新のブラウザでは、 matchAllがその役割を果たします。
const string = "scissors";
const matches = [...string.matchAll(/s/g)];
いくつかの方法で値を取得できます。例えば :
const indexes = matches.map(match => match.index);
これは、関数式(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]
コンパクト(1行)バージョンは次のとおりです。
const findIndices = (str, char) => str.split('').reduce( (indices, letter, index) => { letter === char && indices.push(index); return indices }, [] );
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);
別の代替手段は、を使用することflatMap
です。
var getIndices = (s, t) => {
return [...s].flatMap((char, i) => (char === t ? i + 1 : []));
};
console.log(getIndices('scissors', 's'));
console.log(getIndices('kaios', '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
さらなる解決策として、これが私の解決策です。文字列に存在する文字のインデックスを見つけることができます。
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]
おそらくjavascriptのmatch()関数も使用できます。正規表現を作成し、それをパラメーターとしてmatch()に渡すことができます。
stringName.match(/s/g);
これにより、文字「s」のすべての出現箇所の配列が返されます。