JavaScript Tips | 配列ユーティリティ:並び順保存

JavaScript JavaScript
スポンサーリンク

テーマの整理:「並び順保存」とは何か

「並び順保存」は、ユーザーが並べ替えた配列の順番を、あとで再現できるように“記録しておく”ユーティリティのことです。 業務だと、次のような場面でよく出てきます。

  • 画面でドラッグ&ドロップして並び替えた順番を、次回表示時にも維持したい
  • ユーザーごとに「お気に入りの並び順」を保存しておきたい
  • API から取ってきたデータを「保存済みの並び順」に従って並べたい

ポイントは、「並び替えた配列そのもの」を保存するのではなく、 “並び順を表す情報”を保存しておいて、あとから配列に適用することです。

基本コンセプト:「ID の順番を保存して、あとから並べ替えに使う」

並び順を「配列そのもの」で保存する問題点

例えば、ユーザー一覧を並び替えて、そのまま配列を保存したとします。

const users = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob"   },
];

const reordered = [
  { id: 2, name: "Bob"   },
  { id: 1, name: "Alice" },
];

// この reordered を丸ごと保存する
JavaScript

一見これで良さそうですが、 あとで API から最新のユーザー一覧を取ってきたときに、

  • 新しいユーザーが増えている
  • 既存ユーザーの情報が変わっている

などが起きると、「古い配列をそのまま使う」わけにはいきません。

そこで、「並び順だけ」を保存しておく、という発想が出てきます。

並び順を「ID の配列」として保存する

並び順をこう表現します。

const order = [2, 1]; // id の順番だけを保存
JavaScript

この order を保存しておいて、 あとから最新の users 配列に対して「この順番で並べ替える」ようにします。

これが「並び順保存」の基本コンセプトです。

ユーティリティ 1:並び順(ID 配列)を保存する

シナリオ

ユーザーが UI 上で並び替えた結果として、 並び替え後の配列 reorderedUsers が手元にある。

そこから「並び順だけ」を取り出して保存したい。

実装:extractOrder

function extractOrder(records, idField = "id") {
  if (!Array.isArray(records) || records.length === 0) {
    return [];
  }

  return records.map((r) => r[idField]);
}
JavaScript

重要ポイントの深掘り

「並び順=ID の並び」として定義する 並び順を「レコードそのもの」ではなく「ID の並び」として扱うことで、 あとから最新データに対しても再利用できるようになります。

保存するのはシンプルな配列だけ [2, 1, 5, 3, ...] のような数値・文字列の配列は、 ローカルストレージ・DB・API などに保存しやすく、 シリアライズ(JSON 化)も簡単です。

例題 1:並び替え後の配列から並び順を取り出して保存する

const reorderedUsers = [
  { id: 2, name: "Bob"   },
  { id: 1, name: "Alice" },
];

const order = extractOrder(reorderedUsers);

console.log(order); // [2, 1]
// この order を localStorage や DB に保存しておく
JavaScript

これで、「ユーザーが決めた並び順」を、 軽量な形で保存できました。

ユーティリティ 2:保存した並び順を配列に適用する

シナリオ

次回画面表示時に、API から最新のユーザー一覧を取得した。 同時に、以前保存しておいた order = [2, 1] も読み込んだ。

この 2 つを組み合わせて、「保存済みの並び順」で並べたい。

実装:applyOrder

function applyOrder(records, order, idField = "id") {
  if (!Array.isArray(records) || records.length === 0) {
    return [];
  }
  if (!Array.isArray(order) || order.length === 0) {
    return records.slice(); // 並び順がなければそのまま返す
  }

  const map = new Map();
  records.forEach((r) => {
    map.set(r[idField], r);
  });

  const ordered = [];

  order.forEach((id) => {
    const item = map.get(id);
    if (item) {
      ordered.push(item);
    }
  });

  const usedIds = new Set(order);
  records.forEach((r) => {
    if (!usedIds.has(r[idField])) {
      ordered.push(r);
    }
  });

  return ordered;
}
JavaScript

重要ポイントの深掘り

ID → レコードのマップを作る Map を使って、id からレコードを素早く引けるようにしています。 これで、order の順番に従ってレコードを並べることができます。

order にないレコードも「最後に追加」する 新しく追加されたユーザーなど、 保存済みの order に含まれていないレコードは、 最後にまとめて追加しています。

これにより、

  • 既存ユーザーは「保存済みの並び順」で並ぶ
  • 新規ユーザーは「並び順の末尾」に追加される

という自然な挙動になります。

例題 2:保存済みの並び順を最新ユーザー一覧に適用する

const latestUsers = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob"   },
  { id: 3, name: "Carol" },
];

const savedOrder = [2, 1];

const orderedUsers = applyOrder(latestUsers, savedOrder);

console.log(orderedUsers);
JavaScript

出力イメージはこうなります。

[
  { id: 2, name: "Bob"   }, // savedOrder の 2
  { id: 1, name: "Alice" }, // savedOrder の 1
  { id: 3, name: "Carol" }, // savedOrder にないので最後に追加
]
JavaScript

ここでのポイントは、

  • 「保存済みの並び順」が優先される
  • 新しいデータもちゃんと表示される

というバランスが取れていることです。

ユーティリティ 3:並び順を「ユーザーごと・画面ごと」に保存する

シナリオ

ユーザー A とユーザー B で、 同じ一覧画面でも「好みの並び順」が違う。

また、画面ごとに並び順を変えたい(ユーザー一覧・商品一覧など)。

保存キーの設計

ローカルストレージなどに保存するときは、 「誰の」「どの画面の」並び順かを区別するキーを決めます。

function makeOrderKey(userId, screenId) {
  return `order:${userId}:${screenId}`;
}
JavaScript

実装:saveOrder / loadOrder(ローカルストレージ版)

function saveOrder(key, order) {
  try {
    const json = JSON.stringify(order);
    localStorage.setItem(key, json);
  } catch (e) {
    console.error("並び順の保存に失敗しました", e);
  }
}

function loadOrder(key) {
  try {
    const json = localStorage.getItem(key);
    if (!json) return [];
    const order = JSON.parse(json);
    return Array.isArray(order) ? order : [];
  } catch (e) {
    console.error("並び順の読み込みに失敗しました", e);
    return [];
  }
}
JavaScript

重要ポイントの深掘り

キー設計で「誰の・どの画面の」を区別する order:ユーザーID:画面ID のようなキーにしておくと、 ユーザーごと・画面ごとに並び順を分けて保存できます。

保存・読み込みは“失敗しても壊れない”ようにする 例外が出てもアプリが落ちないように、 try/catch でエラーを握りつぶしつつログだけ出しています。 読み込みに失敗したときは「空の並び順」として扱うことで、 画面は普通に表示されます。

例題 3:ユーザーごと・画面ごとに並び順を保存して適用する

const userId   = "user-123";
const screenId = "user-list";

const key = makeOrderKey(userId, screenId);

const reorderedUsers = [
  { id: 2, name: "Bob"   },
  { id: 1, name: "Alice" },
];

const orderToSave = extractOrder(reorderedUsers);
saveOrder(key, orderToSave);

// 次回表示時
const latestUsers = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob"   },
  { id: 3, name: "Carol" },
];

const savedOrder = loadOrder(key);
const orderedUsers = applyOrder(latestUsers, savedOrder);

console.log(orderedUsers);
JavaScript

これで、

  • ユーザー 123 がユーザー一覧画面で決めた並び順
  • それを次回表示時に再現

という流れが実現できます。

並び順保存ユーティリティで意識してほしい重要ポイント

「並び順=ID の並び」として扱う

並び順保存の一番大事なポイントは、 「並び順そのものではなく、ID の並びを保存する」という発想です。

これによって、

  • 最新データに対しても並び順を再利用できる
  • 保存するデータが軽く・シンプルになる
  • API や DB の変更にも強くなる

というメリットが得られます。

「保存済みの並び順」と「最新データ」をどう統合するかを決める

applyOrder の設計が、並び順保存の“性格”を決めます。

  • order にある ID は、その順番を優先する
  • order にない ID は、最後に追加する
  • order にあるけど、最新データにない ID は無視する

このルールを明確にしておくと、 ユーザーにとって「自然な挙動」になります。

手を動かして「並び順保存」の感覚をつかむ

次のコードを実行して、

  • 並び替え後の配列から並び順を抽出
  • 並び順を保存(ここではメモリ上)
  • 最新データに並び順を適用

という一連の流れを体感してみてください。

function extractOrder(records, idField = "id") {
  if (!Array.isArray(records) || records.length === 0) {
    return [];
  }
  return records.map((r) => r[idField]);
}

function applyOrder(records, order, idField = "id") {
  if (!Array.isArray(records) || records.length === 0) {
    return [];
  }
  if (!Array.isArray(order) || order.length === 0) {
    return records.slice();
  }

  const map = new Map();
  records.forEach((r) => {
    map.set(r[idField], r);
  });

  const ordered = [];
  order.forEach((id) => {
    const item = map.get(id);
    if (item) ordered.push(item);
  });

  const usedIds = new Set(order);
  records.forEach((r) => {
    if (!usedIds.has(r[idField])) {
      ordered.push(r);
    }
  });

  return ordered;
}

function demo() {
  const reorderedUsers = [
    { id: 2, name: "Bob"   },
    { id: 1, name: "Alice" },
  ];

  const order = extractOrder(reorderedUsers);
  console.log("saved order:", order);

  const latestUsers = [
    { id: 1, name: "Alice" },
    { id: 2, name: "Bob"   },
    { id: 3, name: "Carol" },
  ];

  const orderedUsers = applyOrder(latestUsers, order);
  console.log("ordered users:", orderedUsers);
}

demo();
JavaScript

まとめ:並び順保存ユーティリティで「ユーザーの“並べ方の好み”を、ちゃんと覚えておく」

並び順保存は、 「ユーザーが決めた並び方の好みを、ID の並びとして記録し、最新データに適用するためのユーティリティ」です。

プロジェクトでは、例えばこうまとめておくと扱いやすいです。

export function extractOrder(records, idField = "id") { ... }
export function applyOrder(records, order, idField = "id") { ... }
export function makeOrderKey(userId, screenId) { ... }
export function saveOrder(key, order) { ... }
export function loadOrder(key) { ... }
JavaScript

そして、

  • 並び替え操作の直後
  • 画面表示の直前

など、「並び順が変わる・並び順を使う」場面で必ずこのユーティリティを通す。

そうすると、 ユーザーの「この並びが好き」という感覚を、 アプリがちゃんと覚えていてくれるようになります。

配列の中身だけじゃなく、「並び方」まで味方につける—— それが、並び順保存ユーティリティの役割です。

タイトルとURLをコピーしました