如何将数据设置为深度嵌套数组
How to set data to deeply nested array
我正在使用 DevExtreme React Grid Tree。我的初始调用仅填充根行,每个额外的子行都在单击时应用。当有许多嵌套 table 行时,我在应用子行数据时遇到问题。我需要一种有效的方法来找到正确的父行并添加下一个嵌套数组。
这是我已经添加的带有一个嵌套行的 table 数据。
[
{
"area": "Artesia",
"list_id": 45,
"rowId": 158324175700860960,
"parentRowId": 0,
"items": [
{
"area": "Other",
"list_id": 15003,
"rowId": 158324179061139520,
"parentRowId": 158324175700860960
}
]
},
{
"area": "Corpus Christi",
"list_id": 60,
"rowId": 158324175700847800,
"parentRowId": 0,
"items": []
},
{
"area": "Midland",
"list_id": 10,
"rowId": 158324175700867700,
"parentRowId": 0,
"items": [
{
"area": "Delaware Basin",
"list_id": 11001,
"rowId": 158324181266273440,
"parentRowId": 158324175700867700,
"items": []
}
]
},
{
"area": "San Antonio",
"list_id": 63,
"rowId": 158324175700814050,
"parentRowId": 0,
"items": []
}
]
单击 Midland 行后,我将 API return 数据应用为嵌套数组项。
[
{
"area": "Delaware Basin",
"list_id": 11001,
"rowId": 158324181266273440,
"parentRowId": 158324175700867700,
"items": []
}
]
我需要一个可以循环遍历 table 数据的函数,从根级别到无限嵌套行。我现在通过使用 parentId 来匹配 rowId 来匹配数据。
// root table data with one nested row applied to Midland
const tableData = [
{
"area": "Artesia",
"list_id": 45,
"rowId": 158324175700860960,
"parentRowId": 0,
"items": [
{
"area": "Other",
"list_id": 15003,
"rowId": 158324179061139520,
"parentRowId": 158324175700860960
}
]
},
{
"area": "Corpus Christi",
"list_id": 60,
"rowId": 158324175700847800,
"parentRowId": 0,
"items": []
},
{
"area": "Midland",
"list_id": 10,
"rowId": 158324175700867700,
"parentRowId": 0,
"items": [
{
"area": "Delaware Basin",
"list_id": 11001,
"rowId": 158324181266273440,
"parentRowId": 158324175700867700,
"items": []
}
]
},
{
"area": "San Antonio",
"list_id": 63,
"rowId": 158324175700814050,
"parentRowId": 0,
"items": []
}
]
// return data from API after clicking on Delaware Basin
const returnData = [
{
"area": "Delaware Basin Nm",
"list_id": 11007,
"rowId": 158324182577224580,
"parentRowId": 158324181266273440
},
{
"area": "Delaware Basin Tx",
"list_id": 11002,
"rowId": 158324182577248960,
"parentRowId": 158324181266273440
}
]
function applyNestedData (tableData, returnData) {
}
applyNestedData(tableData, returnData)
function applyNestedData (tableData, returnData) {
// use a map to group data by its parentRowId
// in order to insert them together when find matched rowId
const map = new Map()
for (const data of returnData) {
if (map.has(data.parentRowId)) {
map.get(data.parentRowId).push(data)
} else {
map.set(data.parentRowId, [data])
}
}
// Loop tree-structure data by queue
const queue = []
for (const data of tableData) { queue.push(data) }
let data
while (queue.length > 0) {
data = queue.shift()
if (map.has(data.rowId)) {
data.items = data.items.concat(map.get(data.rowId))
}
if (data.items && data.items.length > 1) {
for (const item of data.items) {
queue.push(item)
}
}
}
}
function applyNestedData (tableData, returnData) {
const map = new Map();
returnData.map(data=> {
map.has(data.parentRowId)?
map.get(data.parentRowId).push(data):map.set(data.parentRowId, [data])
});
const queue = [];
tableData.map(data=>{queue.push(data)});
let data;
while (queue.length > 0) {
data = queue.shift();
map.has(data.rowId) && (data.items = data.items.concat(map.get(data.rowId)));
(data.items && data.items.length > 1) && data.items.map(item=> {queue.push(item)})
}
}
我已经为这个问题写了一个解决方案。希望你会喜欢。
请检查我是否在 stackblitz 中创建了:
https://stackblitz.com/edit/js-wurii6
const tableData = [
{
"area": "Artesia",
"list_id": 45,
"rowId": 158324175700860960,
"parentRowId": 0,
"items": [
{
"area": "Other",
"list_id": 15003,
"rowId": 158324179061139520,
"parentRowId": 158324175700860960
}
]
},
{
"area": "Corpus Christi",
"list_id": 60,
"rowId": 158324175700847800,
"parentRowId": 0,
"items": []
},
{
"area": "Midland",
"list_id": 10,
"rowId": 158324175700867700,
"parentRowId": 0,
"items": [
{
"area": "Delaware Basin",
"list_id": 11001,
"rowId": 158324181266273440,
"parentRowId": 158324175700867700,
"items": []
}
]
},
{
"area": "San Antonio",
"list_id": 63,
"rowId": 158324175700814050,
"parentRowId": 0,
"items": []
}
];
const returnData = [
{
"area": "Delaware Basin Nm",
"list_id": 11007,
"rowId": 158324182577224580,
"parentRowId": 158324181266273440
},
{
"area": "Delaware Basin Tx",
"list_id": 11002,
"rowId": 158324182577248960,
"parentRowId": 158324181266273440
}
];
const appResult = document.getElementById('result');
const inputWrapper = {items: tableData};
applyNestedData(inputWrapper, returnData);
function applyNestedData(tableData, returnData){
const { parentRowId } = returnData[0];
const datareturned = findAndUpdate(tableData, returnData, parentRowId);
appResult.innerHTML = JSON.stringify(tableData, undefined, 4)
}
function findAndUpdate(row, returnData, parentRowId){
if(row.rowId && row.rowId == parentRowId){
return true;
} else if (row.items){
let isParent = false;
for(let i=0; row.items && i < row.items.length; i++){
isParent = findAndUpdate(row.items[i], returnData, parentRowId);
if (isParent === true) {
row.items[i].items = returnData;
console.info("found")
break;
}
}
}
return row;
}
<h1>Result</h1>
<pre id="result" style=
"color:green; font-size: 12px; font-weight: bold;">
</pre>
您可以使用一些 dfs 算法简单地遍历树
const tableData = [{ area: 'Artesia ', list_id: 45, rowId: 15836049402342958, parentRowId: 0, Premium: '785', 'Non Premium': '152', Total: '937', items: [] }, { area: 'Corpus Christi ', list_id: 60, rowId: 158360494023429300, parentRowId: 0, Total: '3,098', items: [] }, { area: 'Denver ', list_id: 30, rowId: 158360494023563870, parentRowId: 0, Total: '7,938', items: [] }, { area: 'Fort Worth ', list_id: 14, rowId: 158360494023592130, parentRowId: 0, Total: '14', items: [{ area: 'Southlake', list_id: 1256788, rowId: 12345, parentRowId: 158360494023592130, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [] }] }, { area: 'Midland ', list_id: 10, rowId: 158360494023510200, parentRowId: 0, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [{ area: 'Delaware Basin', list_id: 11001, rowId: 158324181266273440, parentRowId: 158360494023510200, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [] }] }, { area: 'Okc ', list_id: 50, rowId: 158360494023542430, parentRowId: 0, Total: '245', items: [] }, { area: 'San Antonio ', list_id: 63, rowId: 158360494023591680, parentRowId: 0, Total: '4,162', items: [] }]
const returnData = [{ area: 'Delaware Basin Nm', list_id: 11007, rowId: 158324182577224580, parentRowId: 158324181266273440 }, { area: 'Delaware Basin Tx', list_id: 11002, rowId: 158324182577248960, parentRowId: 158324181266273440 }, { area: 'Sub Southlake', list_id: 2345, rowId: 550987654, parentRowId: 12345 }]
const byParentRowId = returnData.reduce((m, it) => {
const v = m.get(it.parentRowId) || []
v.push(it)
m.set(it.parentRowId, v)
return m
}, new Map())
const findRow = (tableData => {
function dfs (data, stopId) {
if (data.rowId === stopId) return data
if (!Array.isArray(data.items)) return []
return data.items.flatMap(x => dfs(x, stopId))
}
return rowId => dfs({ items: tableData }, rowId)[0]
})(tableData)
console.time('setTree1')
;[...byParentRowId.entries()].forEach(([rowId, v]) => (findRow(rowId).items = v))
console.timeEnd('setTree1')
console.log(JSON.stringify({ items: tableData }, null, 2))
请注意,对于每个不同的 parentRowId,您都会遍历树。如果你想变得更精明一点,这会以更多代码为代价,你可以预先构建一个映射 rowId => 节点,并在填充嵌套行时维护它。我建议不要这样做,除非你观察到明显(和有意义的)收益。这里是1ms,没啥用
const tableData = [{ area: 'Artesia ', list_id: 45, rowId: 15836049402342958, parentRowId: 0, Premium: '785', 'Non Premium': '152', Total: '937', items: [] }, { area: 'Corpus Christi ', list_id: 60, rowId: 158360494023429300, parentRowId: 0, Total: '3,098', items: [] }, { area: 'Denver ', list_id: 30, rowId: 158360494023563870, parentRowId: 0, Total: '7,938', items: [] }, { area: 'Fort Worth ', list_id: 14, rowId: 158360494023592130, parentRowId: 0, Total: '14', items: [{ area: 'Southlake', list_id: 1256788, rowId: 12345, parentRowId: 158360494023592130, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [] }] }, { area: 'Midland ', list_id: 10, rowId: 158360494023510200, parentRowId: 0, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [{ area: 'Delaware Basin', list_id: 11001, rowId: 158324181266273440, parentRowId: 158360494023510200, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [] }] }, { area: 'Okc ', list_id: 50, rowId: 158360494023542430, parentRowId: 0, Total: '245', items: [] }, { area: 'San Antonio ', list_id: 63, rowId: 158360494023591680, parentRowId: 0, Total: '4,162', items: [] }]
const returnData = [{ area: 'Delaware Basin Nm', list_id: 11007, rowId: 158324182577224580, parentRowId: 158324181266273440 }, { area: 'Delaware Basin Tx', list_id: 11002, rowId: 158324182577248960, parentRowId: 158324181266273440 }, { area: 'Sub Southlake', list_id: 2345, rowId: 550987654, parentRowId: 12345 }]
const byParentRowId = returnData.reduce((m, it) => {
const v = m.get(it.parentRowId) || []
v.push(it)
m.set(it.parentRowId, v)
return m
}, new Map())
const table = (tableData => {
const rows = new Map()
function dfs (data) {
if (data.rowId) {
rows.set(data.rowId, data)
}
if (!Array.isArray(data.items)) { return }
return data.items.forEach(dfs)
}
dfs({ items: tableData })
return {
setRow: (rowId, items) => {
items.forEach(it => rows.set(it.rowId, it))
const row = rows.get(rowId)
row.items = items
},
getRow: rowId => rows.get(rowId)
}
})(tableData)
console.time('setTree2')
;[...byParentRowId.entries()].forEach(([rowId, v]) => table.setRow(rowId, v))
console.timeEnd('setTree2')
console.log(JSON.stringify({items: tableData},null,2))
您可以像这样创建一个递归函数。
let iterate = (inputdata, item) => {
let id = inputdata.parentRowId;
if (item.rowId == id) {
item.items.push(inputdata);
}
else if (item.items && item.items.length) {
item.items.map(obj => {
iterate(inputdata, obj);
});
}
}
returnData.forEach(inputdata => {
tableData.forEach(item => {
iterate(inputdata, item);
});
});
我正在使用 DevExtreme React Grid Tree。我的初始调用仅填充根行,每个额外的子行都在单击时应用。当有许多嵌套 table 行时,我在应用子行数据时遇到问题。我需要一种有效的方法来找到正确的父行并添加下一个嵌套数组。 这是我已经添加的带有一个嵌套行的 table 数据。
[
{
"area": "Artesia",
"list_id": 45,
"rowId": 158324175700860960,
"parentRowId": 0,
"items": [
{
"area": "Other",
"list_id": 15003,
"rowId": 158324179061139520,
"parentRowId": 158324175700860960
}
]
},
{
"area": "Corpus Christi",
"list_id": 60,
"rowId": 158324175700847800,
"parentRowId": 0,
"items": []
},
{
"area": "Midland",
"list_id": 10,
"rowId": 158324175700867700,
"parentRowId": 0,
"items": [
{
"area": "Delaware Basin",
"list_id": 11001,
"rowId": 158324181266273440,
"parentRowId": 158324175700867700,
"items": []
}
]
},
{
"area": "San Antonio",
"list_id": 63,
"rowId": 158324175700814050,
"parentRowId": 0,
"items": []
}
]
单击 Midland 行后,我将 API return 数据应用为嵌套数组项。
[
{
"area": "Delaware Basin",
"list_id": 11001,
"rowId": 158324181266273440,
"parentRowId": 158324175700867700,
"items": []
}
]
我需要一个可以循环遍历 table 数据的函数,从根级别到无限嵌套行。我现在通过使用 parentId 来匹配 rowId 来匹配数据。
// root table data with one nested row applied to Midland
const tableData = [
{
"area": "Artesia",
"list_id": 45,
"rowId": 158324175700860960,
"parentRowId": 0,
"items": [
{
"area": "Other",
"list_id": 15003,
"rowId": 158324179061139520,
"parentRowId": 158324175700860960
}
]
},
{
"area": "Corpus Christi",
"list_id": 60,
"rowId": 158324175700847800,
"parentRowId": 0,
"items": []
},
{
"area": "Midland",
"list_id": 10,
"rowId": 158324175700867700,
"parentRowId": 0,
"items": [
{
"area": "Delaware Basin",
"list_id": 11001,
"rowId": 158324181266273440,
"parentRowId": 158324175700867700,
"items": []
}
]
},
{
"area": "San Antonio",
"list_id": 63,
"rowId": 158324175700814050,
"parentRowId": 0,
"items": []
}
]
// return data from API after clicking on Delaware Basin
const returnData = [
{
"area": "Delaware Basin Nm",
"list_id": 11007,
"rowId": 158324182577224580,
"parentRowId": 158324181266273440
},
{
"area": "Delaware Basin Tx",
"list_id": 11002,
"rowId": 158324182577248960,
"parentRowId": 158324181266273440
}
]
function applyNestedData (tableData, returnData) {
}
applyNestedData(tableData, returnData)
function applyNestedData (tableData, returnData) {
// use a map to group data by its parentRowId
// in order to insert them together when find matched rowId
const map = new Map()
for (const data of returnData) {
if (map.has(data.parentRowId)) {
map.get(data.parentRowId).push(data)
} else {
map.set(data.parentRowId, [data])
}
}
// Loop tree-structure data by queue
const queue = []
for (const data of tableData) { queue.push(data) }
let data
while (queue.length > 0) {
data = queue.shift()
if (map.has(data.rowId)) {
data.items = data.items.concat(map.get(data.rowId))
}
if (data.items && data.items.length > 1) {
for (const item of data.items) {
queue.push(item)
}
}
}
}
function applyNestedData (tableData, returnData) {
const map = new Map();
returnData.map(data=> {
map.has(data.parentRowId)?
map.get(data.parentRowId).push(data):map.set(data.parentRowId, [data])
});
const queue = [];
tableData.map(data=>{queue.push(data)});
let data;
while (queue.length > 0) {
data = queue.shift();
map.has(data.rowId) && (data.items = data.items.concat(map.get(data.rowId)));
(data.items && data.items.length > 1) && data.items.map(item=> {queue.push(item)})
}
}
我已经为这个问题写了一个解决方案。希望你会喜欢。
请检查我是否在 stackblitz 中创建了: https://stackblitz.com/edit/js-wurii6
const tableData = [
{
"area": "Artesia",
"list_id": 45,
"rowId": 158324175700860960,
"parentRowId": 0,
"items": [
{
"area": "Other",
"list_id": 15003,
"rowId": 158324179061139520,
"parentRowId": 158324175700860960
}
]
},
{
"area": "Corpus Christi",
"list_id": 60,
"rowId": 158324175700847800,
"parentRowId": 0,
"items": []
},
{
"area": "Midland",
"list_id": 10,
"rowId": 158324175700867700,
"parentRowId": 0,
"items": [
{
"area": "Delaware Basin",
"list_id": 11001,
"rowId": 158324181266273440,
"parentRowId": 158324175700867700,
"items": []
}
]
},
{
"area": "San Antonio",
"list_id": 63,
"rowId": 158324175700814050,
"parentRowId": 0,
"items": []
}
];
const returnData = [
{
"area": "Delaware Basin Nm",
"list_id": 11007,
"rowId": 158324182577224580,
"parentRowId": 158324181266273440
},
{
"area": "Delaware Basin Tx",
"list_id": 11002,
"rowId": 158324182577248960,
"parentRowId": 158324181266273440
}
];
const appResult = document.getElementById('result');
const inputWrapper = {items: tableData};
applyNestedData(inputWrapper, returnData);
function applyNestedData(tableData, returnData){
const { parentRowId } = returnData[0];
const datareturned = findAndUpdate(tableData, returnData, parentRowId);
appResult.innerHTML = JSON.stringify(tableData, undefined, 4)
}
function findAndUpdate(row, returnData, parentRowId){
if(row.rowId && row.rowId == parentRowId){
return true;
} else if (row.items){
let isParent = false;
for(let i=0; row.items && i < row.items.length; i++){
isParent = findAndUpdate(row.items[i], returnData, parentRowId);
if (isParent === true) {
row.items[i].items = returnData;
console.info("found")
break;
}
}
}
return row;
}
<h1>Result</h1>
<pre id="result" style=
"color:green; font-size: 12px; font-weight: bold;">
</pre>
您可以使用一些 dfs 算法简单地遍历树
const tableData = [{ area: 'Artesia ', list_id: 45, rowId: 15836049402342958, parentRowId: 0, Premium: '785', 'Non Premium': '152', Total: '937', items: [] }, { area: 'Corpus Christi ', list_id: 60, rowId: 158360494023429300, parentRowId: 0, Total: '3,098', items: [] }, { area: 'Denver ', list_id: 30, rowId: 158360494023563870, parentRowId: 0, Total: '7,938', items: [] }, { area: 'Fort Worth ', list_id: 14, rowId: 158360494023592130, parentRowId: 0, Total: '14', items: [{ area: 'Southlake', list_id: 1256788, rowId: 12345, parentRowId: 158360494023592130, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [] }] }, { area: 'Midland ', list_id: 10, rowId: 158360494023510200, parentRowId: 0, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [{ area: 'Delaware Basin', list_id: 11001, rowId: 158324181266273440, parentRowId: 158360494023510200, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [] }] }, { area: 'Okc ', list_id: 50, rowId: 158360494023542430, parentRowId: 0, Total: '245', items: [] }, { area: 'San Antonio ', list_id: 63, rowId: 158360494023591680, parentRowId: 0, Total: '4,162', items: [] }]
const returnData = [{ area: 'Delaware Basin Nm', list_id: 11007, rowId: 158324182577224580, parentRowId: 158324181266273440 }, { area: 'Delaware Basin Tx', list_id: 11002, rowId: 158324182577248960, parentRowId: 158324181266273440 }, { area: 'Sub Southlake', list_id: 2345, rowId: 550987654, parentRowId: 12345 }]
const byParentRowId = returnData.reduce((m, it) => {
const v = m.get(it.parentRowId) || []
v.push(it)
m.set(it.parentRowId, v)
return m
}, new Map())
const findRow = (tableData => {
function dfs (data, stopId) {
if (data.rowId === stopId) return data
if (!Array.isArray(data.items)) return []
return data.items.flatMap(x => dfs(x, stopId))
}
return rowId => dfs({ items: tableData }, rowId)[0]
})(tableData)
console.time('setTree1')
;[...byParentRowId.entries()].forEach(([rowId, v]) => (findRow(rowId).items = v))
console.timeEnd('setTree1')
console.log(JSON.stringify({ items: tableData }, null, 2))
请注意,对于每个不同的 parentRowId,您都会遍历树。如果你想变得更精明一点,这会以更多代码为代价,你可以预先构建一个映射 rowId => 节点,并在填充嵌套行时维护它。我建议不要这样做,除非你观察到明显(和有意义的)收益。这里是1ms,没啥用
const tableData = [{ area: 'Artesia ', list_id: 45, rowId: 15836049402342958, parentRowId: 0, Premium: '785', 'Non Premium': '152', Total: '937', items: [] }, { area: 'Corpus Christi ', list_id: 60, rowId: 158360494023429300, parentRowId: 0, Total: '3,098', items: [] }, { area: 'Denver ', list_id: 30, rowId: 158360494023563870, parentRowId: 0, Total: '7,938', items: [] }, { area: 'Fort Worth ', list_id: 14, rowId: 158360494023592130, parentRowId: 0, Total: '14', items: [{ area: 'Southlake', list_id: 1256788, rowId: 12345, parentRowId: 158360494023592130, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [] }] }, { area: 'Midland ', list_id: 10, rowId: 158360494023510200, parentRowId: 0, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [{ area: 'Delaware Basin', list_id: 11001, rowId: 158324181266273440, parentRowId: 158360494023510200, Premium: '7,743', 'Non Premium': '2,584', Total: '10,327', items: [] }] }, { area: 'Okc ', list_id: 50, rowId: 158360494023542430, parentRowId: 0, Total: '245', items: [] }, { area: 'San Antonio ', list_id: 63, rowId: 158360494023591680, parentRowId: 0, Total: '4,162', items: [] }]
const returnData = [{ area: 'Delaware Basin Nm', list_id: 11007, rowId: 158324182577224580, parentRowId: 158324181266273440 }, { area: 'Delaware Basin Tx', list_id: 11002, rowId: 158324182577248960, parentRowId: 158324181266273440 }, { area: 'Sub Southlake', list_id: 2345, rowId: 550987654, parentRowId: 12345 }]
const byParentRowId = returnData.reduce((m, it) => {
const v = m.get(it.parentRowId) || []
v.push(it)
m.set(it.parentRowId, v)
return m
}, new Map())
const table = (tableData => {
const rows = new Map()
function dfs (data) {
if (data.rowId) {
rows.set(data.rowId, data)
}
if (!Array.isArray(data.items)) { return }
return data.items.forEach(dfs)
}
dfs({ items: tableData })
return {
setRow: (rowId, items) => {
items.forEach(it => rows.set(it.rowId, it))
const row = rows.get(rowId)
row.items = items
},
getRow: rowId => rows.get(rowId)
}
})(tableData)
console.time('setTree2')
;[...byParentRowId.entries()].forEach(([rowId, v]) => table.setRow(rowId, v))
console.timeEnd('setTree2')
console.log(JSON.stringify({items: tableData},null,2))
您可以像这样创建一个递归函数。
let iterate = (inputdata, item) => {
let id = inputdata.parentRowId;
if (item.rowId == id) {
item.items.push(inputdata);
}
else if (item.items && item.items.length) {
item.items.map(obj => {
iterate(inputdata, obj);
});
}
}
returnData.forEach(inputdata => {
tableData.forEach(item => {
iterate(inputdata, item);
});
});