Saya menggunakan .splice() untuk menghapus objek dari larik objek yang berisi stempel waktu, berdasarkan apakah userDates berisi stempel waktu yang cocok atau stempel waktu dalam rentang 45 menit sebelum atau setelah stempel waktu objek. Pada dasarnya menghapus semua objek dengan nilai tanggal yang tumpang tindih dengan nilai tanggal larik userDates.

Saat Anda menjalankan kode ini, Anda akan melihat bahwa beberapa objek dihapus, tetapi yang lain tidak.

JSFiddle: https://jsfiddle.net/jb2t3Lr9/1/ dan kode untuk mereproduksi masalah:

let userDates = ["2020-11-20T22:00:00.000Z","2020-11-20T23:00:00.000Z","2020-11-21T00:00:00.000Z","2020-11-21T01:00:00.000Z","2020-11-22T02:15:00.000Z","2020-11-22T03:15:00.000Z","2020-11-22T01:00:00.000Z","2020-11-22T00:00:00.000Z","2020-11-21T23:00:00.000Z","2020-12-13T22:00:00.000Z","2020-12-14T22:00:00.000Z","2020-12-15T22:00:00.000Z","2020-12-16T22:00:00.000Z","2020-12-13T23:00:00.000Z","2020-12-14T23:00:00.000Z","2020-11-21T20:00:00.000Z","2020-11-22T20:00:00.000Z","2020-11-22T19:00:00.000Z","2020-11-21T19:00:00.000Z"];

let datesToUpdate = [
  { sessionInterval: 50, dateTime: '2020-11-22T20:00:00.000Z' },
  { sessionInterval: 50, dateTime: '2020-11-21T20:00:00.000Z' },
  { sessionInterval: 50, dateTime: '2020-11-21T19:00:00.000Z' },
  { sessionInterval: 50, dateTime: '2020-11-22T19:00:00.000Z' },
  { sessionInterval: 50, dateTime: '2020-11-22T17:30:00.000Z' },
  { sessionInterval: 50, dateTime: '2020-11-21T17:00:00.000Z' }
];


function removeOverlappingDates(userDates, datesToUpdate) {
  const FIFTEEN_MINUTES = 15 * 60 * 1000; // milliseconds
  datesToUpdate.forEach((toUpdate, index) => {
    userDates.forEach((date) => {
      let dateInMS = new Date("" + date).valueOf();
      const fifteenBefore = dateInMS - FIFTEEN_MINUTES;
      const thirtyBefore = dateInMS - FIFTEEN_MINUTES * 2;
      const fortyFiveBefore = dateInMS - FIFTEEN_MINUTES * 3;
      const fifteenAfter = dateInMS + FIFTEEN_MINUTES;
      const thirtyAfter = dateInMS + FIFTEEN_MINUTES * 2;
      const fortyFiveAfter = dateInMS + FIFTEEN_MINUTES * 3;
      let toUpdateInMS = new Date("" + toUpdate.dateTime).valueOf();
      if (
        toUpdateInMS == fifteenBefore ||
        toUpdateInMS == thirtyBefore ||
        toUpdateInMS == fortyFiveBefore ||
        toUpdateInMS == fifteenAfter ||
        toUpdateInMS == thirtyAfter ||
        toUpdateInMS == fortyFiveAfter ||
        toUpdateInMS == dateInMS
      ) {
        datesToUpdate.splice(index, 1);
      }
    });
  });

  return datesToUpdate;
}

console.log("datesToUpdate 1", datesToUpdate);
datesToUpdate = removeOverlappingDates(userDates, datesToUpdate);
console.log("datesToUpdate 2", datesToUpdate);

Yang lebih aneh lagi bagi saya adalah jika saya hanya membandingkan array nilai datetime satu sama lain (dengan nilai datetime yang sama dengan array objek), maka semuanya akan dihapus dengan benar. Biola: https://jsfiddle.net/rc1mvzLq/

0
robertfoenix 20 November 2020, 12:21

1 menjawab

Jawaban Terbaik

Saya akan mencoba menulis ini dengan metode baru yang minimal, tetapi seperti yang disebutkan dalam komentar, filter sangat ideal untuk kasus penggunaan ini.

Pertama dan terpenting, jangan pernah mengubah larik yang Anda ulangi. Itu menyebabkan perilaku yang sulit untuk di-debug. Namun, salinan larik di awal tidak akan membantu Anda dalam kasus ini karena Anda menggunakan splice untuk menghapus elemen larik di tengahnya yang menyebabkan sekelompok elemen diindeks ulang.

Misalnya jika Anda memiliki [A,B,C,D,E] dan Anda menghapus elemen pada indeks 1, Anda sekarang memiliki [A,C,D,E,F] dan (karena iterasi untuk indeks itu selesai) indeks Anda bertambah dan sekarang 2 dan Anda tidak akan pernah menguji nilai C dalam logika Anda. Beberapa situasi lagi seperti ini dan Anda dapat melihat bagaimana banyak elemen dibiarkan tidak dicentang. Satu-satunya cara ini bisa berhasil adalah jika dua elemen yang perlu dihapus tidak pernah bersebelahan.

Untuk menjaga ini tetap sederhana dan sedekat mungkin dengan logika asli Anda, yang saya sarankan adalah Anda menghitung berapa banyak elemen yang telah Anda hapus dan mengimbangi indeks dengan jumlah itu. Namun juga salin array sehingga Anda tidak mengubah yang Anda ulangi (CATATAN: salinan dangkal sudah cukup, dan Anda cukup menggunakan sintaksis penyebaran untuk membuat larik baru dengan objek sama).

function removeOverlappingDates(userDates, datesToUpdate) {
  const FIFTEEN_MINUTES = 15 * 60 * 1000; // milliseconds
  const newDatesToUpdate = [...datesToUpdate];
  let deletedElementsCount = 0;
  datesToUpdate.forEach((toUpdate, index) => {
    // same code as before
      if (
        // check if this condition should maybe be toUpdateInMS >= fortyFiveBefore && toUpdateInMS <= fortyFiveAfter
      ) {
        const newIndex = index - deletedElementsCount;
        newDatesToUpdate.splice(newIndex, 1);
        deletedElementsCount = deletedElementsCount + 1;
      } 
    });
  });

  return newDatesToUpdate;
}

Sebagai catatan tambahan, ada alasan mengapa salinannya yang saya ubah dan itu karena datesToUpdate dilewatkan sebagai argumen fungsi. Jika array datesToUpdate diubah di dalam fungsi, itu akan tetap berubah setelahnya. Anda tidak boleh mengubah objek argumen (ini termasuk array) di dalam fungsi kecuali jika Anda ingin tetap seperti itu. Fungsi yang melakukan ini dianggap memiliki efek samping dan ini juga dapat sulit untuk di-debug jika tidak digunakan dengan hati-hati. Dalam kasus Anda, tidak perlu melakukan efek samping karena Anda mengembalikan hasilnya.

1
5ar 20 November 2020, 10:19