JavaScriptのマップとセットでデータ構造を最適化する方法

JavaScriptのマップとセットでデータ構造を最適化する方法

JavaScriptのMapとSetは、効率的にデータを管理するための柔軟なデータ構造です。これらを活用することで、従来のオブジェクトや配列では難しいタスクを簡単に解決できます。本記事では、それぞれの特徴や実用的な利用方法を詳しく解説します。

Mapの基本構造と用途

Mapはキーと値のペアを保存するデータ構造で、任意の型のキーを使用できます。

// Mapの基本操作
const map = new Map();
map.set('name', 'Alice');
map.set('age', 25);

console.log(map.get('name')); // Alice
console.log(map.has('age')); // true
console.log(map.size); // 2

Mapの利点

オブジェクトと比較した場合のMapの利点を挙げます。

// オブジェクトの欠点
const obj = {};
obj['1'] = 'Number as string';
obj[1] = 'Number as number';
console.log(obj['1']); // 'Number as number'

// Mapの利点
const map = new Map();
map.set('1', 'Number as string');
map.set(1, 'Number as number');
console.log(map.get('1')); // 'Number as string'
console.log(map.get(1)); // 'Number as number'

Setの基本構造と用途

Setは一意の値を保持するデータ構造で、重複を自動的に排除します。

// Setの基本操作
const set = new Set();
set.add(1);
set.add(2);
set.add(2); // 重複は無視される

console.log(set.has(1)); // true
console.log(set.size); // 2

Setを使用したユニーク値の抽出

配列から一意の値を取り出す方法です。

const numbers = [1, 2, 2, 3, 4, 4];
const uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers); // [1, 2, 3, 4]

MapとSetのイテレーション

for…ofループを使用して値を反復処理します。

// Mapの反復処理
const map = new Map([['name', 'Alice'], ['age', 25]]);
for (const [key, value] of map) {
  console.log(`${key}: ${value}`);
}

// Setの反復処理
const set = new Set([1, 2, 3]);
for (const value of set) {
  console.log(value);
}

MapとSetの変換

他のデータ構造との相互変換の方法です。

// Mapからオブジェクトへの変換
const map = new Map([['name', 'Alice'], ['age', 25]]);
const obj = Object.fromEntries(map);
console.log(obj); // { name: 'Alice', age: 25 }

// 配列からSetへの変換
const arr = [1, 2, 3];
const set = new Set(arr);
console.log(set); // Set { 1, 2, 3 }

WeakMapとWeakSetの概要

WeakMapとWeakSetの基本的な特徴と用途を示します。

// WeakMapの使用例
let obj = { key: 'value' };
const weakMap = new WeakMap();
weakMap.set(obj, 'some value');
obj = null; // ガベージコレクションで解放される

// WeakSetの使用例
let obj2 = { data: 'important' };
const weakSet = new WeakSet();
weakSet.add(obj2);
obj2 = null; // ガベージコレクションで解放される

パフォーマンス比較

Mapとオブジェクト、Setと配列のパフォーマンスの違いを比較します。

// Map vs オブジェクト
console.time('Map');
const map = new Map();
for (let i = 0; i < 100000; i++) {
  map.set(i, i);
}
console.timeEnd('Map');

console.time('Object');
const obj = {};
for (let i = 0; i < 100000; i++) {
  obj[i] = i;
}
console.timeEnd('Object');

Mapを使用したカスタムデータストア

Mapを利用して柔軟なデータストアを実現します。

class DataStore {
  constructor() {
    this.store = new Map();
  }
  add(key, value) {
    this.store.set(key, value);
  }
  get(key) {
    return this.store.get(key);
  }
  delete(key) {
    this.store.delete(key);
  }
}

const ds = new DataStore();
ds.add('name', 'Alice');
console.log(ds.get('name')); // Alice
ds.delete('name');
console.log(ds.get('name')); // undefined

Setを使用したタグ管理システム

Setを活用して重複のないタグ管理を行います。

class TagManager {
  constructor() {
    this.tags = new Set();
  }
  addTag(tag) {
    this.tags.add(tag);
  }
  removeTag(tag) {
    this.tags.delete(tag);
  }
  hasTag(tag) {
    return this.tags.has(tag);
  }
}

const manager = new TagManager();
manager.addTag('JavaScript');
manager.addTag('WebDev');
console.log(manager.hasTag('JavaScript')); // true
manager.removeTag('JavaScript');
console.log(manager.hasTag('JavaScript')); // false

MapとSetの組み合わせ

MapとSetを組み合わせて複雑なデータ管理を実現します。

const map = new Map();
map.set('user1', new Set(['read', 'write']));
map.set('user2', new Set(['read']));

console.log(map.get('user1').has('write')); // true
console.log(map.get('user2').has('write')); // false

まとめ

MapとSetを活用することで、柔軟かつ効率的なデータ構造を設計できます。キーと値の管理にはMap、一意性の確保にはSetを使用することで、従来のデータ構造に比べて明確で高速なコードを実現できます。