1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaScript オブジェクトの持つ値で要素を検証するSet

Posted at

JavaScriptで集合演算の記事に @miumiu0917 さんから、JavaScriptのSetはユーザ定義なオブジェクトが扱えないとコメントを頂いた。

たしかに、MDN Setの冒頭にSetはプリミティブかオブジェクトの参照を対象にしていると書いてあった。

The Set object lets you store unique values of any type, whether primitive values or object references.

例えば、配列を要素とするSetでは、配列の実体をそのまま入れると、配列の要素の値が同じでも別物として扱われてしまう。

example1.js
arrayA = [1,2];
arrayB = [3,4];
set1 = new Set([arrayA, arrayB]);
set2 = new Set([arrayA]);
set3 = new Set([[1,2]]);

set2.isSubset(set1);
// true

set3.isSubset(set1);
// false

※ isSubsetについてはJavaScriptで集合演算を御覧ください。

内容で要素を検証するSet

Setを拡張すれば、配列やユーザ定義のオブジェクトの持つ値で要素を検証するようにできるのでは、と思ったのでやってみた。

ContentSetという名前でSetを継承したクラスを作ってみた。変えたのは hasadd

has は親クラスの hastrue ならそのままで、 false なら自分の要素を操作して一致しているかを検証するコードを足した。

JavaScriptは演算子の上書きができないみたいなので、値の同一性をどうやって検証しようかちょっと悩んだ。JavaScriptで配列やオブジェクトを比較して等しいかチェックする方法で、一旦JSONでシリアライズして比較しているのを見つけ、それに倣った。

add は拡張した has で検証してから値を足すようにした。

contentset.js
class ContentSet extends Set {
	has(value){
		if(super.has(value)){
        	return true;
    	}
	    for (var elem of this) {
    	    if (JSON.stringify(value) === JSON.stringify(elem)) {
        	    return true;
        	}
    	}
		return false;
    }
	add(value){
		if(this.has(value)){
			return;
        }
		super.add(value);
    }
}

ChromeとFirefoxのJavaScript Consoleで実行してみたけど、期待どおりに動いているみたい。

example2.js
a = new ContentSet([[1]]);
// Set(1) {Array(1)}
a.has([1]);
// true
a.add([1]);
// undefined
a
// Set(1) {Array(1)}
a.size;
// 1
b = new ContentSet([[1], [1]]);
// Set(1) {Array(1)}
b
// Set(1) {Array(1)}

冒頭の例をContentSetで実行してみたけど、こちらも期待どおり。(Chromeで確認)

example1.js
arrayA = [1,2];
arrayB = [3,4];
set1 = new ContentSet([arrayA, arrayB]);
set2 = new ContentSet([arrayA]);
set3 = new ContentSet([[1,2]]);

set2.isSubset(set1);
// true

set3.isSubset(set1);
// true

感想

  • JSONでシリアライズして文字列として比較しているので、オブジェクトの要素の順序とか大丈夫なのかよくわからないけど、とりあえず動いている。
  • 毎回シリアライズするので遅そう。
  • コンストラクタとかはとくに変えてないけど、挙動が変わっているということは、ちゃんと自分の has を使ってくれているのだろうと思う。
  • それなら add も変えなくてよさそうだけど、それだと要素が重複してしまったので必要な改変だったようだ。

JavaScriptは素人なので、間違っているかもしれないけど、ご参考まで。

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?