0
0
この記事誰得? 私しか得しないニッチな技術で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

reduce関数を使ってオブジェクト配列の中身をマージする

Last updated at Posted at 2024-07-03

結論

マージ関数
const reduceSameProducts = (Orders: Order[]) => {
  return Orders.reduce<Order[]>((acc, currentOrder) => {
    // ここはマージする条件
    if (acc[acc.length-1] &&
        acc[acc.length-1].name === currentOrder.name
    ) {
      // マージする処理
      const processedOrder: Order = {
        ...acc[acc.length-1],
        quantity: acc[acc.length-1].quantity + currentOrder.quantity,
      }
      return [processedOrder]
    } else {
      // マージ対象ではなかったらスキップ
      acc.push(currentOrder);
      return acc;
    }
  }, []);
}

解説

以下のOrderデータオブジェクトを想定します。

Order
type Order = {
  name: string;
  price: number;
  quantity: number;
}

そして以下のようなOrder[]があったとします。

Order[]
const orders: Order[] = [
  { name: 'トマト', price: 100, quantity: 1 },
  { name: 'トマト', price: 100, quantity: 2 },
  { name: 'マンゴー', price: 200, quantity: 1 },
  { name: 'イチゴ', price: 250, quantity: 3 }
];

トマトが被っていますね。
これを以下のようにマージしたい。

マージ
[
  { name: 'トマト', price: 100, quantity: 3 },
  { name: 'マンゴー', price: 200, quantity: 1 },
  { name: 'イチゴ', price: 250, quantity: 3 }
];

トマトの個数をまとめました。
しかしこれをまとめるのが意外と難しい。
現在の要素と一つ前の要素を比較してゴニョゴニョする必要がありそうです。
reduce が使えそうです。

最初の要素は空配列にします。

最初
type Order = {
  name: string;     // 商品名
  price: number;    // 値段
  quantity: number; // 個数
}

const orders: Order[] = [
  { name: 'トマト', price: 100, quantity: 1 },
  { name: 'トマト', price: 100, quantity: 2 },
  { name: 'マンゴー', price: 200, quantity: 1 },
  { name: 'イチゴ', price: 250, quantity: 3 }
];

const reduceSameProducts = (Orders: Order[]) => {
  return Orders.reduce<Order[]>((acc, currentOrder) => {}, []);
}

accaccumulator です。前回の

(acc, currentOrder) => {}

の呼び出し結果です。
商品名が一致しているかどうかで処理を変更するので、そうでない場合は現在の値をそのまま結果に突っ込む必要があります。
ここで以下のように処理を書きます。

ステップ1
const reduceSameProducts = (Orders: Order[]) => {
  return Orders.reduce<Order[]>((acc, currentOrder) => {
    // ここはマージする条件
    if (acc[acc.length-1] &&
        acc[acc.length-1].name === currentOrder.name
    ) {
      
    } else {
      // マージ対象ではなかったらスキップ
      acc.push(currentOrder);
      return acc;
    }
  }, []);
}

acc[acc.length-1] は、1回目の時に undefinedになるため、そこの条件分岐のために入れています。
acc[acc.length-1].name === currentOrder.name は一つ前の結果と比べるための条件です。
マージする条件は以下でも可です。

const existingOrder = acc.find(order => order.name === currentOrder.name);

そして実際のマージ処理です。
一つ前の結果(現在の値でもいいです)の処理しないプロパティを展開して、対象のプロパティを処理します。

const processedOrder: Order = {
    ...acc[acc.length-1],
    quantity: acc[acc.length-1].quantity + currentOrder.quantity,
  }

こうすることで、以下のように値が変わります。

結果
[{
  "name": "トマト",
  "price": 100,
  "quantity": 3
}, {
  "name": "マンゴー",
  "price": 200,
  "quantity": 1
}, {
  "name": "イチゴ",
  "price": 250,
  "quantity": 3
}] 

おわりに

もっといいやり方があったら教えてください。

0
0
2

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
0
0