วนซ้ำผ่านวัตถุของวัตถุ
ฉันกำลังพยายามเขียนฟังก์ชันวนซ้ำเพื่อตรวจสอบวัตถุและส่งคืนรายการตาม ID ฉันสามารถทำให้ส่วนแรกของสิ่งนี้ทำงานได้ แต่ฉันมีช่วงเวลาที่ยากลำบากในการพยายามเรียกใช้ฟังก์ชันนี้ในลักษณะวนซ้ำและสามารถใช้สายตาใหม่ได้ โค้ดอยู่ด้านล่าง เมื่อคุณเรียกใช้ข้อมูลโค้ดคุณจะได้รับอาร์เรย์ 6 รายการซึ่งสำหรับการทำซ้ำครั้งแรกคือสิ่งที่ฉันต้องการ แต่ฉันจะเรียกฟังก์ชันของฉันด้วยพารามิเตอร์ที่เหมาะสมเพื่อรับรายการที่ซ้อนกันได้อย่างไร เป้าหมายสุดท้ายของฉันคือการมีวัตถุทั้งหมดที่ขึ้นต้นด้วย 'Cstm' ซึ่งเป็นวัตถุที่ซ้อนกันด้วยเพื่อเพิ่มลงในอาร์เรย์ tableAndValues ฉันพยายามสร้างแบบจำลองโค้ดของฉันหลังจากนี้: รับค่าคีย์ทั้งหมดจาก JavaScript อาร์เรย์ที่ซ้อนกันหลายระดับแต่สิ่งนี้เกี่ยวข้องกับอาร์เรย์ของวัตถุไม่ใช่วัตถุของวัตถุ คำแนะนำหรือคำแนะนำใด ๆ ที่ฉันได้รับจะชื่นชมมาก
JSFiddle: https://jsfiddle.net/xov49jLs/
const response = {
"data": {
"Cstm_PF_ADG_URT_Disposition": {
"child_welfare_placement_value": ""
},
"Cstm_PF_ADG_URT_Demographics": {
"school_grade": "family setting",
"school_grade_code": ""
},
"Cstm_Precert_Medical_Current_Meds": [
{
"med_name": "med1",
"dosage": "10mg",
"frequency": "daily"
},
{
"med_name": "med2",
"dosage": "20mg",
"frequency": "daily"
}
],
"Cstm_PF_ADG_URT_Substance_Use": {
"dimension1_comment": "dimension 1 - tab1",
"Textbox1": "text - tab1"
},
"Cstm_PF_ADG_Discharge_Note": {
"prior_auth_no_comm": "auth no - tab2"
},
"Cstm_PF_ADG_URT_Clinical_Plan": {
"cca_cs_dhs_details": "details - tab2"
},
"container": {
"Cstm_PF_Name": {
"first_name": "same text for textbox - footer",
"last_name": "second textbox - footer"
},
"Cstm_PF_ADG_URT_Demographics": {
"new_field": "mapped demo - footer"
},
"grid2": [
{
"Cstm_PF_ADG_COMP_Diagnosis": {
"diagnosis_label": "knee",
"diagnosis_group_code": "leg"
}
},
{
"Cstm_PF_ADG_COMP_Diagnosis": {
"diagnosis_label": "ankle",
"diagnosis_group_code": "leg"
}
}
]
},
"submit": true
}
};
function getNamesAndValues(data, id) {
const tablesAndValues = [],
res = data;
Object.entries(res).map(([key, value]) => {
const newKey = key.split('_')[0].toLowerCase();
// console.log(newKey) // -> 'cstm'
if (newKey === id) {
tablesAndValues.push({
table: key,
values: value
});
} else {
// I can log value and key and see what I want to push
// to the tablesAndValues array, but I can't seem to get
// how to push the nested items.
// console.log(value);
// console.log(key);
// getNamesAndValues(value, key)
}
});
return tablesAndValues;
}
console.log(getNamesAndValues(response.data, 'cstm'));
คำตอบ
เพื่อให้ได้ผลลัพธ์ด้วยการกดเพียงครั้งเดียวเราสามารถส่งตารางผลลัพธ์ไปยังฟังก์ชันเมื่อเรียกซ้ำได้ แต่เริ่มต้นเป็นตารางว่างในการโทรครั้งแรก ฉันเปลี่ยน.map
ไปด้วย.forEach
เนื่องจากไม่ได้ใช้ค่าส่งคืน:
const response = {
"data": {
"Cstm_PF_ADG_URT_Disposition": {
"child_welfare_placement_value": ""
},
"Cstm_PF_ADG_URT_Demographics": {
"school_grade": "family setting",
"school_grade_code": ""
},
"Cstm_Precert_Medical_Current_Meds": [
{
"med_name": "med1",
"dosage": "10mg",
"frequency": "daily"
},
{
"med_name": "med2",
"dosage": "20mg",
"frequency": "daily"
}
],
"Cstm_PF_ADG_URT_Substance_Use": {
"dimension1_comment": "dimension 1 - tab1",
"Textbox1": "text - tab1"
},
"Cstm_PF_ADG_Discharge_Note": {
"prior_auth_no_comm": "auth no - tab2"
},
"Cstm_PF_ADG_URT_Clinical_Plan": {
"cca_cs_dhs_details": "details - tab2"
},
"container": {
"Cstm_PF_Name": {
"first_name": "same text for textbox - footer",
"last_name": "second textbox - footer"
},
"Cstm_PF_ADG_URT_Demographics": {
"new_field": "mapped demo - footer"
},
"grid2": [
{
"Cstm_PF_ADG_COMP_Diagnosis": {
"diagnosis_label": "knee",
"diagnosis_group_code": "leg"
}
},
{
"Cstm_PF_ADG_COMP_Diagnosis": {
"diagnosis_label": "ankle",
"diagnosis_group_code": "leg"
}
}
]
},
"submit": true
}
};
function getNamesAndValues(data, id, tablesAndValues = []) {
const res = data;
Object.entries(res).forEach(([key, value]) => {
const newKey = key.split('_')[0].toLowerCase();
if (newKey === id) {
tablesAndValues.push({
table: key,
values: value
});
} else {
getNamesAndValues( value, id, tablesAndValues); }
});
return tablesAndValues;
}
console.log(getNamesAndValues(response.data, 'cstm'));
คุณเพียงแค่ต้องเรียก push to tablesAndValues ภายในคำสั่ง else กับตัวดำเนินการที่เหลือและส่งค่าและ id เป็นพารามิเตอร์
const response = {
"data": {
"Cstm_PF_ADG_URT_Disposition": {
"child_welfare_placement_value": ""
},
"Cstm_PF_ADG_URT_Demographics": {
"school_grade": "family setting",
"school_grade_code": ""
},
"Cstm_Precert_Medical_Current_Meds": [
{
"med_name": "med1",
"dosage": "10mg",
"frequency": "daily"
},
{
"med_name": "med2",
"dosage": "20mg",
"frequency": "daily"
}
],
"Cstm_PF_ADG_URT_Substance_Use": {
"dimension1_comment": "dimension 1 - tab1",
"Textbox1": "text - tab1"
},
"Cstm_PF_ADG_Discharge_Note": {
"prior_auth_no_comm": "auth no - tab2"
},
"Cstm_PF_ADG_URT_Clinical_Plan": {
"cca_cs_dhs_details": "details - tab2"
},
"container": {
"Cstm_PF_Name": {
"first_name": "same text for textbox - footer",
"last_name": "second textbox - footer"
},
"Cstm_PF_ADG_URT_Demographics": {
"new_field": "mapped demo - footer"
},
"grid2": [
{
"Cstm_PF_ADG_COMP_Diagnosis": {
"diagnosis_label": "knee",
"diagnosis_group_code": "leg"
}
},
{
"Cstm_PF_ADG_COMP_Diagnosis": {
"diagnosis_label": "ankle",
"diagnosis_group_code": "leg"
}
}
]
},
"submit": true
}
};
function getNamesAndValues(data, id) {
const tablesAndValues = [],
res = data;
Object.entries(res).map(([key, value]) => {
const newKey = key.split('_')[0].toLowerCase();
// console.log(newKey) // -> 'cstm'
if (newKey === id) {
tablesAndValues.push({
table: key,
values: value
});
} else {
// I can log value and key and see what I want to push
// to the tablesAndValues array, but I can't seem to get
// how to push the nested items.
// console.log(value);
// console.log(key);
tablesAndValues.push(...getNamesAndValues(value, id))
}
});
return tablesAndValues;
}
console.log(getNamesAndValues(response.data, 'cstm'));
หรือสั้นกว่า
function getNamesAndValues2(data, id) {
return Object.entries(data).reduce((arr, [key, value]) => {
arr.push(
...(key.split('_')[0].toLowerCase() === id ? [{ table: key, values: value }] : getNamesAndValues(value, id))
);
return arr
}, []);
}
นี่คือเวอร์ชันที่ใช้งานได้ ฉันเรียกฟังก์ชันหลักแบบวนซ้ำถ้าค่าเป็นอาร์เรย์หรือวัตถุ ส่งผ่านในสถานะปัจจุบันของอาร์เรย์การนับแต่ละครั้ง
function getNamesAndValues(data, id, tablesAndValues = []) {
const res = data;
Object.entries(res).map(([key, value]) => {
const newKey = key.split('_')[0].toLowerCase();
const item = res[key];
if (newKey === id) {
tablesAndValues.push({
table: key,
values: value
});
}
if(Array.isArray(item)) {
return item.map(el => getNamesAndValues(el, id, tablesAndValues));
}
if(typeof item === 'object') {
return getNamesAndValues(item, id, tablesAndValues);
}
})
return tablesAndValues;
}
console.log(getNamesAndValues(response.data, 'cstm'));
นี่เป็นอีกแนวทางหนึ่งโดยใช้เครื่องกำเนิดไฟฟ้า -
const keySearch = (t = [], q = "") =>
filter(t, ([ k, _ ]) => String(k).startsWith(q))
const r =
Array.from
( keySearch(response, "Cstm")
, ([ table, values ]) =>
({ table, values })
)
console.log(r)
[
{
table: 'Cstm_PF_ADG_URT_Disposition',
values: { child_welfare_placement_value: '' }
},
{
table: 'Cstm_PF_ADG_URT_Demographics',
values: { school_grade: 'family setting', school_grade_code: '' }
},
{
table: 'Cstm_Precert_Medical_Current_Meds',
values: [ [Object], [Object] ]
},
{
table: 'Cstm_PF_ADG_URT_Substance_Use',
values: {
dimension1_comment: 'dimension 1 - tab1',
Textbox1: 'text - tab1'
}
},
{
table: 'Cstm_PF_ADG_Discharge_Note',
values: { prior_auth_no_comm: 'auth no - tab2' }
},
{
table: 'Cstm_PF_ADG_URT_Clinical_Plan',
values: { cca_cs_dhs_details: 'details - tab2' }
},
{
table: 'Cstm_PF_Name',
values: {
first_name: 'same text for textbox - footer',
last_name: 'second textbox - footer'
}
},
{
table: 'Cstm_PF_ADG_URT_Demographics',
values: { new_field: 'mapped demo - footer' }
},
{
table: 'Cstm_PF_ADG_COMP_Diagnosis',
values: { diagnosis_label: 'knee', diagnosis_group_code: 'leg' }
},
{
table: 'Cstm_PF_ADG_COMP_Diagnosis',
values: { diagnosis_label: 'ankle', diagnosis_group_code: 'leg' }
}
]
ด้านบนkeySearch
เป็นเพียงความเชี่ยวชาญของfilter
-
function* filter (t = [], test = v => v)
{ for (const v of traverse(t)){
if (test(v))
yield v
}
}
ซึ่งเป็นความเชี่ยวชาญของtraverse
-
function* traverse (t = {})
{ if (Object(t) === t)
for (const [ k, v ] of Object.entries(t))
( yield [ k, v ]
, yield* traverse(v)
)
}
ขยายตัวอย่างด้านล่างเพื่อยืนยันผลลัพธ์ในเบราว์เซอร์ของคุณ -
function* traverse (t = {})
{ if (Object(t) === t)
for (const [ k, v ] of Object.entries(t))
( yield [ k, v ]
, yield* traverse(v)
)
}
function* filter (t = [], test = v => v)
{ for (const v of traverse(t)){
if (test(v))
yield v
}
}
const keySearch = (t = [], q = "") =>
filter(t, ([ k, _ ]) => String(k).startsWith(q))
const response =
{"data":{"Cstm_PF_ADG_URT_Disposition":{"child_welfare_placement_value":""},"Cstm_PF_ADG_URT_Demographics":{"school_grade":"family setting","school_grade_code":""},"Cstm_Precert_Medical_Current_Meds":[{"med_name":"med1","dosage":"10mg","frequency":"daily"},{"med_name":"med2","dosage":"20mg","frequency":"daily"}],"Cstm_PF_ADG_URT_Substance_Use":{"dimension1_comment":"dimension 1 - tab1","Textbox1":"text - tab1"},"Cstm_PF_ADG_Discharge_Note":{"prior_auth_no_comm":"auth no - tab2"},"Cstm_PF_ADG_URT_Clinical_Plan":{"cca_cs_dhs_details":"details - tab2"},"container":{"Cstm_PF_Name":{"first_name":"same text for textbox - footer","last_name":"second textbox - footer"},"Cstm_PF_ADG_URT_Demographics":{"new_field":"mapped demo - footer"},"grid2":[{"Cstm_PF_ADG_COMP_Diagnosis":{"diagnosis_label":"knee","diagnosis_group_code":"leg"}},{"Cstm_PF_ADG_COMP_Diagnosis":{"diagnosis_label":"ankle","diagnosis_group_code":"leg"}}]},"submit":true}}
const result =
Array.from
( keySearch(response, "Cstm")
, ([ table, values ]) =>
({ table, values })
)
console.log(result)
คำตอบที่เรียกซ้ำอย่างสมเหตุสมผลอาจมีลักษณะดังนี้:
const getNamesAndValues = (obj) =>
Object (obj) === obj
? Object .entries (obj)
.flatMap (([k, v]) => [
... (k .toLowerCase () .startsWith ('cstm') ? [{table: k, value: v}] : []),
... getNamesAndValues (v)
])
: []
const response = {data: {Cstm_PF_ADG_URT_Disposition: {child_welfare_placement_value: ""}, Cstm_PF_ADG_URT_Demographics: {school_grade: "family setting", school_grade_code: ""}, Cstm_Precert_Medical_Current_Meds: [{med_name: "med1", dosage: "10mg", frequency: "daily"}, {med_name: "med2", dosage: "20mg", frequency: "daily"}], Cstm_PF_ADG_URT_Substance_Use: {dimension1_comment: "dimension 1 - tab1", Textbox1: "text - tab1"}, Cstm_PF_ADG_Discharge_Note: {prior_auth_no_comm: "auth no - tab2"}, Cstm_PF_ADG_URT_Clinical_Plan: {cca_cs_dhs_details: "details - tab2"}, container: {Cstm_PF_Name: {first_name: "same text for textbox - footer", last_name: "second textbox - footer"}, Cstm_PF_ADG_URT_Demographics: {new_field: "mapped demo - footer"}, grid2: [{Cstm_PF_ADG_COMP_Diagnosis: {diagnosis_label: "knee", diagnosis_group_code: "leg"}}, {Cstm_PF_ADG_COMP_Diagnosis: {diagnosis_label: "ankle", diagnosis_group_code: "leg"}}]}, submit: true}}
console .log (getNamesAndValues (response))
.as-console-wrapper {max-height: 100% !important; top: 0}
แต่นี่ไม่ง่ายอย่างที่ฉันต้องการ รหัสนี้ผสมการค้นหารายการที่ตรงกันและการทดสอบที่ใช้ในการค้นหานั้นร่วมกับการจัดรูปแบบของผลลัพธ์ หมายความว่าเป็นฟังก์ชันแบบกำหนดเองที่ทั้งซับซ้อนในการทำความเข้าใจและใช้ซ้ำได้น้อยกว่าที่ฉันต้องการ
ฉันต้องการใช้ฟังก์ชันที่ใช้ซ้ำได้โดยแยกคุณสมบัติสามประการของฟังก์ชันนี้ออก ดังนั้นในขณะที่สิ่งต่อไปนี้เกี่ยวข้องกับโค้ดหลายบรรทัด แต่ฉันคิดว่ามันสมเหตุสมผลกว่า:
const findAllDeep = (pred) => (obj) =>
Object (obj) === obj
? Object .entries (obj)
.flatMap (([k, v]) => [
... (pred (k, v) ? [[k, v]] : []),
... findAllDeep (pred) (v)
])
: []
const makeSimpleObject = (name1, name2) => ([k, v]) =>
({[name1]: k, [name2]: v})
const makeSimpleObjects = (name1, name2) => (xs) =>
xs .map (makeSimpleObject (name1, name2))
const cstmTest = k =>
k .toLowerCase () .startsWith ('cstm')
const getNamesAndValues = (obj) =>
makeSimpleObjects ('table', 'values') (findAllDeep (cstmTest) (obj))
const response = {data: {Cstm_PF_ADG_URT_Disposition: {child_welfare_placement_value: ""}, Cstm_PF_ADG_URT_Demographics: {school_grade: "family setting", school_grade_code: ""}, Cstm_Precert_Medical_Current_Meds: [{med_name: "med1", dosage: "10mg", frequency: "daily"}, {med_name: "med2", dosage: "20mg", frequency: "daily"}], Cstm_PF_ADG_URT_Substance_Use: {dimension1_comment: "dimension 1 - tab1", Textbox1: "text - tab1"}, Cstm_PF_ADG_Discharge_Note: {prior_auth_no_comm: "auth no - tab2"}, Cstm_PF_ADG_URT_Clinical_Plan: {cca_cs_dhs_details: "details - tab2"}, container: {Cstm_PF_Name: {first_name: "same text for textbox - footer", last_name: "second textbox - footer"}, Cstm_PF_ADG_URT_Demographics: {new_field: "mapped demo - footer"}, grid2: [{Cstm_PF_ADG_COMP_Diagnosis: {diagnosis_label: "knee", diagnosis_group_code: "leg"}}, {Cstm_PF_ADG_COMP_Diagnosis: {diagnosis_label: "ankle", diagnosis_group_code: "leg"}}]}, submit: true}}
console .log (findAllDeep (cstmTest) (response))
.as-console-wrapper {max-height: 100% !important; top: 0}
นี่คือฟังก์ชั่นตัวช่วยทั้งหมดของระดับการใช้ซ้ำที่แตกต่างกัน:
makeSimpleObject
ใช้ชื่อคีย์สองชื่อพูด'foo'
และ'bar'
และส่งคืนฟังก์ชันที่ใช้อาร์เรย์สององค์ประกอบพูด[10, 20]
และส่งคืนวัตถุที่ตรงกับสิ่งเหล่านั้นเช่น{foo: 10, bar: 20}
makeSimpleObjects
makeSimpleObjects('foo', 'bar')([[8, 6], [7, 5], [30, 9]]) //=> [{foo: 8, bar: 6}, {foo: 7, bar: 5}, {foo: 30, bar: 9}]
จะเป็นสิ่งเดียวกันสำหรับอาร์เรย์ของอาร์เรย์สององค์ประกอบ:cstmTest
เป็นเพรดิเคตง่ายๆที่ใช้ทดสอบว่าคีย์ขึ้นต้น (ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่) ด้วย"cstm"
หรือไม่และ
findAllDeep
รับเพรดิเคตและส่งคืนฟังก์ชันที่รับอ็อบเจกต์และส่งคืนอาร์เรย์ของอาร์เรย์สององค์ประกอบโดยถือคู่คีย์ / ค่าสำหรับรายการใด ๆ ที่ตรงกับเพรดิเคต (เพรดิเคตมีให้ทั้งคีย์และค่าในกรณีปัจจุบันเราต้องการเพียงคีย์ แต่ดูเหมือนว่าจะสมเหตุสมผลสำหรับฟังก์ชันที่จะรับอย่างใดอย่างหนึ่ง
ฟังก์ชันหลักของเราgetNamesAndValues
ใช้findAllDeep (cstmTest)
เพื่อค้นหาค่าที่ตรงกันจากนั้นจึงmakeSimpleObjects ('table', 'values')
แปลงผลลัพธ์เป็นรูปแบบสุดท้าย
โปรดทราบว่าfindAllDeep
, makeSimpleObject
และmakeSimpleObjects
ฟังก์ชั่นทั้งหมดน่าจะเป็นที่อื่น ๆ ที่มีประโยชน์ การปรับแต่งที่นี่มีเฉพาะในcstmTest
และในคำจำกัดความสั้น ๆ สำหรับgetNamesAndValues
. ฉันจะนับว่าเป็นชัยชนะ