Petakan / Kurangi objek JSON multi level
Saya memiliki daftar penyelamatan untuk pengemudi ambulans di berbagai negara bagian yang ditampilkan di papan kanban. Objek JSON saya dibagi dengan status penyelamatan, dan kemudian dikelompokkan berdasarkan pengemudi. Strukturnya seperti ini:
--Status (belum ditugaskan / ditugaskan / tiba / diselamatkan)
---- Kelompok pengemudi
------- Daftar penyelamatan
Penyelamatan memiliki tanggal waktu dan lintang / bujur yang terkait dengannya, jadi saya dapat menggunakan map / reduce untuk menemukan penyelamatan yang paling baru dihadiri oleh pengemudi, dan menunjukkan lokasi itu di peta.
Satu masalah adalah bahwa kelompok pengemudi bisa ada di satu swimlane dan tidak ada yang lain.
Saya ingin : memfilter daftar ke status tiba / diselamatkan saja, (meskipun secara logis ini mungkin tidak diperlukan karena tidak mungkin memiliki waktu kedatangan tanpa terkait driver, tetapi ini di luar cakupan) dan untuk setiap grup pengemudi mengembalikan penyelamatan terakhir mereka pada waktu kedatangan atau waktu penyelamatan. Ini akan meninggalkan saya dengan daftar grup driver yang berbeda, dengan hanya penyelamatan terbaru untuk grup itu
Inilah kode kerja:
let groups = cases
.filter(swimlane => parseInt(swimlane.rescueStatus) >= 3)
.map(groups => groups.rescuerGroups)
.map(rescuerGroups => rescuerGroups)
.reduce((result, current) => {
if(result.length === 0){
return current;
}
else{
current.forEach(currentRescueGroup => {
let index = result.findIndex(parentRescueGroup => {
return parseInt(parentRescueGroup.rescuer1) == parseInt(currentRescueGroup.rescuer1) &&
parseInt(parentRescueGroup.rescuer2) == parseInt(currentRescueGroup.rescuer2)
})
index > -1 ?
result[index].rescues = result[index].rescues.concat(currentRescueGroup.rescues)
:
result.push(currentRescueGroup);
})
return result;
}}, [])
.map(rescueGroup => {
let maxRescue = rescueGroup.rescues.reduce((current, previous) => {
let currentTime = new Date(current.ambulanceArrivalTime) > (new Date(current.rescueTime) || new Date(1901, 01, 01)) ? current.ambulanceArrivalTime : current.rescueTime;
let previousTime = new Date(previous.ambulanceArrivalTime) > (new Date(previous.rescueTime) || new Date(1901, 01, 01)) ? previous.ambulanceArrivalTime : previous.rescueTime;
return previousTime > currentTime ? current : previous;
})
return {
rescuer1Abbreviation: rescueGroup.rescuer1Abbreviation,
rescuer2Abbreviation: rescueGroup.rescuer2Abbreviation,
latestLocation: maxRescue.latLngLiteral,
rescues: rescueGroup.rescues
}
})
Dan inilah JSBin termasuk kode kerja:
https://jsbin.com/hocasob/edit?js,console
Bantuan apa pun untuk menyederhanakan bagian pengurangan akan sangat kami hargai
Jawaban
Mengubah komentar menjadi ulasan (saya memberikan implementasi alternatif, tetapi ide-ide dasar dapat diterapkan untuk implementasi OP).
Pertama, beberapa pemikiran umum. Seperti yang saya sebutkan di komentar tentang parseIntfungsinya, linter dapat membantu menemukan masalah apa pun. Salah satu yang populer adalah ESLint . Tapi mungkin lebih tepatnya, data tampaknya sudah berupa angka, jadi tidak perlu menguraikannya.
Ini dapat membantu untuk sedikit membersihkan kode dengan mengekstrak filter, reduksi, pembuat peta, penyortir, dll. Di luar sebagai variabel dan memberi mereka nama deskriptif, misalnya:
// filter
const arrivedOrRescued = ({rescueStatus}) => rescueStatus >= 3
// sorter
const byArrivalOrRescueTime = (a, b) =>
Date.parse(a.ambulanceArrivalTime || a.rescueTime)
- Date.parse(b.ambulanceArrivalTime || b.rescueTime)
// reducer
const byRescuers = (acc, {rescuerGroups}) => {
rescuerGroups.forEach(({
rescues
, rescuer1Abbreviation: r1
, rescuer2Abbreviation: r2
}) => {
let group = `${r1}-${r2}`
acc.has(group) ? acc.get(group).push(...rescues) : acc.set(group, rescues)
})
return acc
}
jadi mendapatkan Map(hanya sebuah contoh) oleh penyelamat dari swimlanes kemudian bisa menjadi
let rescuers = cases.filter(arrivedOrRescued).reduce(byRescuer, new Map())
dan menyortir penyelamatan mereka bisa menjadi
rescuers.forEach((rescues, abbrevs) => rescues.sort(byArrivalOrRescueTime))
setelah itu penyelamatan terakhir adalah elemen terakhir dari larik yang sekarang telah dikumpulkan menjadi satu larik dan disortir.
Satu hal yang ingin saya promosikan di sini ketika ada objek bersarang yang agak rumit dalam data, adalah menggunakan komentar JSDoc untuk mendokumentasikan bentuk data. Sebagai contoh:
/*
* @typedef {Object} Swimlane
* @property {Array.<RescuerGroup>} rescuerGroups
* @property {Number} rescueStatus
* @property {String} rescueStatusName
*
* @typedef {Object} RescuerGroup
* @property {Array.<Rescue>} rescues
* @property {?Number} rescuer1
* @property {?Number} rescuer2
* @property {?String} rescuer1Abbreviation
* @property {?String} rescuer2Abbreviation
*
* @typedef {Object} Rescue
* @property {?String} ambulanceArrivalTime
* @property {?String} callDateTime
* @property {?String} callerName
* @property {String} callerNumber
* @property {?Number} callOutcomeId
* @property {Number} emergencyCaseId
* @property {Number} emergencyCodeId
* @property {Number} emergencyNumber
* @property {Number} isLargeAnimal
* @property {Number} latitude
* @property {Number} longitude
* @property {{lat: Number, lng: Number}} latLngLiteral
* @property {String} location
* @property {Array.<String>} patients
* @property {Number} rescuer1
* @property {Number} rescuer2
* @property {?String} rescueTime
* @property {Number} RescueStatus
*/
Ini mempermudah orang lain terutama dalam transformasi data.
Hanya catatan bahwa saya belum menguji semua ini, jadi ambil kode di atas dengan sebutir garam. Selain itu, banyak yang mungkin akan meminta saya untuk menggunakan lebih banyak tanda kurung dan titik koma.