💭

Ionicで活用できる連想配列を結合するヘルパーメソッド

2020/12/17に公開
秘伝のタレです。きれいに書き直したという方はぜひ教えてください。

Ionicでは、 Infinite ScrollRefresher を通して、コンテンツの続きの読み込みや再読み込みを行います。もちろん、 Infinite Scroll する時は、現在のコンテンツIDをPOSTして続きだけ読み込んだり、 Refresher では既存のアイテムをすべて消去して読み込み直したりすることが多いのですが、バックエンドの設計であったり、もしくは「削除されたコンテンツもあるので、現在の読み込みコンテンツとマージさせたい」みたいなことも起こります。具体的にはこんな感じですね。

・ タイムラインのいいね数などが変わってる可能性あるから、最新15件だけは上書きを続けたい
・ いくつかの配列は削除されてる可能性があるから上書きして削除を反映したい
・ 更新日が変わってるので、過去の該当配列だけ削除して、最新にもってきたい

まぁ、連想配列の結合って、いろいろ考え出すと要件多いんですよね。「ID順に並べるけど、同一IDだった場合は、作成時間で昇順にしたい」とか。
で、もう秘伝のタレと化しつつあるのですが、そういった私の要望を反映させるためにつくった連想配列結合メソッドを公開します。

 public ArrayConcatById<T>(
    arrayOld: T[],
    arrayNew: T[],
    key: string,
    order: string = 'DESC',
    secondaryKey: string = null,
  ): T[] {
    if (!arrayNew.length && !arrayOld.length) {
      return [];
    }
    const lead = arrayNew[0][key] as number;
    const last = arrayNew[arrayNew.length - 1][key] as number;

    arrayOld = arrayOld || [];
    arrayNew = arrayNew || [];
    arrayOld = arrayOld.filter((vol) => {
      return (
        (lead > last && ((vol[key] as number) >= lead || (vol[key] as number) <= last)) ||
        (lead < last && ((vol[key] as number) <= lead || (vol[key] as number) >= last)) ||
        (lead as number) === (last as number)
      );
    });

    let old: T[];
    if (secondaryKey !== null) {
      old = arrayOld.filter((vol) => {
        let flg = true;
        arrayNew.forEach((element) => {
          if (element[secondaryKey] === vol[secondaryKey]) {
            flg = false;
          }
        });
        return flg;
      });
    } else {
      old = arrayOld;
    }

    const oldData = old.filter((vol) => {
      let flg = true;
      arrayNew.forEach((element) => {
        if (element[key] === vol[key]) {
          flg = false;
        }
      });
      return flg;
    });
    let data = arrayNew.concat(oldData);

    // デフォは降順(DESC)
    let ord = -1;

    if (order === 'ASC') {
      // 指定があれば昇順(ASC)
      console.log('ASC');
      ord = 1;
    }

    data = data.sort((a, b) => {
      const x = a[key] as number;
      const y = b[key] as number;
      if (x > y) {
        return ord;
      }
      if (x < y) {
        return ord * -1;
      }
      return 0;
    });

    return data;
  }

ヘルパーにして、以下のように使います。なお、ソートするためのIDは必ず数字が入ります。

this.items = this.helper.ArrayConcatById<Interface>(this.items, newItems, 'id', 'ASC');

「配列の結合、concatだと要件満たせないなぁ」という方はぜひご利用ください。そして、リファクタリングしてもっときれいに書いたらそっと教えてください。というか、今久々に見直したけど、書き直したいなこれ・・・。

それではまた。

Discussion