質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

4回答

25604閲覧

ある文字列に対して、配列に入っている文字列のどれかに一致する判定をシンプルに書きたい

fagai

総合スコア2158

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

1グッド

2クリップ

投稿2016/02/24 03:31

編集2016/02/24 04:12

こんにちは。

現在私はNodeJS5.6を利用してnodejsアプリケーションを開発しています。

その際に、以下の様なソースを書くこととなりました。

javascript

1var words = ['sample', 'alert', 'community']; 2var input = '<a>abcabacaa,sample,aaaaa</a>'; 3var match = false; 4for(var i = 0; i < words.length; i++) { 5 if(input.search(words[i]) != -1) { 6 match = true; 7 break; 8 } 9}

これでも問題なく動くのですが、words配列の文字列は最大300件くらいになるので負荷なども考えてシンプルな形にしたいと考えています。

なお入力の際、「,目的の文字列,」というカンマで囲う形になるのは確定しています。
inputは<a>abcabacaa,sample,aaaaa</a><a>abcabacaa,corp,aaaaa</a>のようになる場合もあります。

何かアドバイスをいただけたら幸いです。
よろしくお願いいたします。

ikuwow👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

String.prototype.indexOf を使う(部分一致)

String.prototype.search は正規表現オブジェクトでコストが高いので String.prototype.indexOf が良いと思います。
node.js で使えるか分かりませんが、可能なら String.prototype.includes の方が高速かもしれません(ブラウザの最適化による)。
また、原理的には繰り返し文で最速は while 文になります。

JavaScript

1var words = ['sample', 'alert', 'community'], 2 input = '<a>abcabacaa,sample,aaaaa</a>', 3 i = words.length; 4 5input = input.replace(/^<[^>]*>|<[^>]*>$/g, ''); // 余計な文字列は削っておく 6 7while (i--) { 8 if (input.indexOf(words[i]) !== -1) { 9 // フラグ変数 match を使わず、ここでマッチした時の処理もやっておく 10 console.log(words[i]); // "sample" 11 break; 12 } 13}

これでも問題なく動くのですが、words配列の文字列は最大300件くらいになるので負荷なども考えてシンプルな形にしたいと考えています。

誤解されがちですが、「最速のコード」が「最小のコード」とは限りません。
関数はコストが重いのでパフォーマンスを稼ぐ為に StatementExpression にしてコードが長くなる事もあります。

Array.prototype.indexOf を使う(完全一致)

単語の照合が完全一致でよければ Array.prototype.indexOf を利用可能です。
また、inputsplit で分解した単語数が words の単語数(300)を下回っている場合は検索対象を逆転する事で繰り返し処理の回数を下げる事が可能です。

JavaScript

1'use strict'; 2var words = ['sample', 'alert', 'community'], 3 input = '<a>abcabacaa,sample,aaaaa</a>'.replace(/^<[^>]*>|<[^>]*>$/g, '').split(','), 4 i = input.length; 5 6while (i--) { 7 if (words.indexOf(input[i]) !== -1) { 8 // フラグ変数 match を使わず、ここでマッチした時の処理もやっておく 9 console.log(input[i]); // "sample" 10 break; 11 } 12}

(2016/02/24 13:20追記) Array.prototype.indexOf のコードを追加しました。

Re: fagai さん

投稿2016/02/24 04:01

編集2016/02/24 04:21
think49

総合スコア18156

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fagai

2016/02/24 04:08

回答ありがとうございます! なるほど!String.prototype.indexOfというのがあるんですね。 whileが一番早いというのも初めて知りました・・・。 ありがとうございます!
think49

2016/02/24 04:43 編集

ちょっと気になったのですが、 var words = ['sample', 'alert', 'community'], input = '<a>abcabacaa,samplehoge,aaaaa</a>'; の場合でもHITしますが、これは期待通りの動作でしょうか。 部分一致ならこのままで構いませんが、完全一致で単語を照合するならアルゴリズム上の問題があると思います。 完全一致なら input.split(','); して Array#indexOf で走査すると良いと思います。
fagai

2016/02/24 04:15 編集

,sample,というのは確定で、必ず1キーワードしか入らないので大丈夫です。 とおもいましたが、それは期待していませんでした。。。! なるほど!inputの方をsplitする形ですね。
think49

2016/02/24 04:23

親記事に Array.prototype.indexOf のコードを追加しました。 input の単語数はどれぐらいでしょうか。 今回の事例では input を split した数が3なので繰り返し回数は3回で済みます。
fagai

2016/02/24 04:46

<chat thread="XXXXXXXX" no="XXXXXX" date="XXXXXX" date_usec="XXXXX" user_id="XXXX" premium="XXX">XXXXXX,単語,XXXXXX</chat> こんなデータが幾つかくっついてくることもありますし、1件しか来ないことも有ります。 ぶっちゃけた話、ニコニコ生放送の放送開始通知メッセージです。
think49

2016/02/24 04:49

ならば、「input の単語数 < words の単語数」でしょうから「input を繰り返し処理」する方が試行回数が減ってよいと思います。
fagai

2016/02/24 05:11

ありがとうございます! この方法で行こうと思います!
guest

0

あるか否かを判別したいだけであれば、連想配列を使うと良いと思います。
wordsを連想配列に。
input側を単語に分割

投稿2016/02/24 03:35

編集2016/02/24 03:37
t_obara

総合スコア5488

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fagai

2016/02/24 03:39

回答ありがとうございます! jsには連想配列は無いと思うのですが、どうでしょうか? サーチアルゴリズムとは例えばどのようなものでしょうか?
maisumakun

2016/02/24 04:06 編集

ただのオブジェクトを用意するだけで、大体は実行できます。var obj ={hoge: true, piyo: true, fuga: true}というようにあれば、obj[item]は、itemがhoge、piyo、fugaのどれかの場合だけtrueになります。
t_obara

2016/02/24 04:17

wordsを良い具合にソートするなど、検索効率を上げることも可能です。 http://qiita.com/alucky0707/items/10052866719ba5c5f5d7 ちょっと古いですが、この辺りを参考に wordsがどのようにメンテ・修正され、inputがどのくらいの頻度でそこに含まれる文字列がどれくらいかにより、チューニングをすることになるかと思います。
think49

2016/02/24 04:46

qiita の Search について。試みは面白いのですが、[[Prototype]] 上のプロパティも拾う実装になっているのが残念ですね…。 console.log(new Search(['sample', 'alert', 'community']).has('hasOwnProperty')); // true hasOwnProperty もしくは Object.create(null); を使えば解決できると思います。
fagai

2016/02/24 04:51

このような方法もあるんですねー。参考になります!
guest

0

要Underscore.jsなので、参考程度ではありますが紹介しておきます。
こういった配列処理その他に使える便利な関数が用意されているので、導入を検討する余地はあるかもしれません。

_.intersection(*arrays) ... 全ての配列に存在する値のみを抽出する。
なので、今回の場合は抽出された配列のlengthが1以上ならマッチしたということになります。

var words = ['sample', 'alert', 'community'], input = '<a>abcabacaa,sample,aaaaa</a>'.replace(/^<[^>]*>|<[^>]*>$/g, '').split(','), match = _.intersection(words, input).length > 0; console.log(match); // true

投稿2016/02/24 04:59

編集2016/02/24 05:01
yamato_hikawa

総合スコア2092

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fagai

2016/02/24 05:10

ありがとうございます!
guest

0

inputの形式は変わらないですか?カンマ区切りは何個くらいを想定しますか?
300件程度でしたら今のままでも良いと思います。
カンマ区切りの数が300以下であれば、inputのデータをsplitしてループ回数が
少なくなるなら負荷が軽減できると思います。

投稿2016/02/24 03:40

hato_pato

総合スコア215

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fagai

2016/02/24 03:57 編集

回答ありがとうございます! inputの形式は質問に提示したような文字列が続けて入る場合もありますが多くても10個くらいです。(<a>abcabacaa,sample,aaaaa</a><a>abcabacaa,corp,aaaaa</a>) ただし、inputは絶え間なくリクエストされる感じです。(1秒に5,6回くらいです。コメントサーバーからコメントを取得しています) 個人的にはforで300回くらい回すことになる点を懸念しています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問