javascript - 如何使用根节点项按顺序遍历嵌套 JSON
问题描述
我有一个嵌套的 JSON 结构,就像一个播放列表可以有图像、视频,这个播放列表也可以有另一个嵌套的播放列表。
所以我希望得到输出,就像我从头到尾遍历最顶层的播放列表时一样,让它嵌套/子播放列表的项目只是落在最顶层循环索引中的项目。
到目前为止,我已经尝试过了
<html>
<head>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script>
$.getJSON( "https://5da7520623fa7400146975dd.mockapi.io/api/playlist", function(data){
iterate(data.contents, 3)
});
//*******response is received and passed, all your logic goes here*********
function iterate(contents, maxRound) {
for(i = 1; i <= maxRound; i++) {
parse(contents,i)
}
}
function parse(contents, cycle) {
$.each(contents, function(i, content) {
if(content.type == "playlist") {
var contentsLength = content.contents.length
var indexForRound = cycle % contentsLength
if(contentsLength == cycle) {
indexForRound = contentsLength - 1
}else {
indexForRound = indexForRound - 1
}
const onlyContentToChild = content.contents[indexForRound]
parse([onlyContentToChild], 1)
}else {
$("#contents").append('<li> '+ content.name +' </li>');
}
});
}
</script>
</head>
<body>
<ol id="contents">
</ol>
</body>
</html>
注意:调用 API 即获取播放列表返回与示例二匹配的响应
解决方案
这是一个简单的递归解决方案
const myData = { contents: [{ name: 'image 1', type: 'file' }, { name: 'playlist 1', type: 'playlist', level: 1, contents: [{ name: 'image 3', type: 'file' }, { name: 'playlist 101', type: 'playlist', level: 2, contents: [{ name: 'image 101', type: 'file' }, { name: 'image 102', type: 'file' }, { name: 'image 103', type: 'file' }, { name: 'image 104', type: 'file' }] }, { name: 'image 4', type: 'file' }] }, { name: 'image 2', type: 'file' }, { name: 'playlist 2', type: 'playlist', level: 1, contents: [{ name: 'image 5', type: 'file' }, { name: 'image 6', type: 'file' }, { name: 'image 7', type: 'file' }] }] };
const Iterator = (data) => {
const state = { idx: -1 };
const next = (curData, curState) => {
if (curData.type === 'file') {
return curData.name;
}
if (!('contents' in curState)) {
curState.contents = Array.from(
{ length: curData.contents.length },
() => ({ idx: -1 })
);
}
curState.idx = (curState.idx + 1) % curData.contents.length;
return next(curData.contents[curState.idx], curState.contents[curState.idx]);
};
return () => Array.from(
{ length: data.contents.length },
() => next(data, state)
);
};
const next = Iterator(myData);
for (let idx = 0; idx < 13; idx += 1) {
console.log(next());
}
// => [ 'image 1', 'image 3', 'image 2', 'image 5' ]
// => [ 'image 1', 'image 101', 'image 2', 'image 6' ]
// => [ 'image 1', 'image 4', 'image 2', 'image 7' ]
// => [ 'image 1', 'image 3', 'image 2', 'image 5' ]
// => [ 'image 1', 'image 102', 'image 2', 'image 6' ]
// => [ 'image 1', 'image 4', 'image 2', 'image 7' ]
// => [ 'image 1', 'image 3', 'image 2', 'image 5' ]
// => [ 'image 1', 'image 103', 'image 2', 'image 6' ]
// => [ 'image 1', 'image 4', 'image 2', 'image 7' ]
// => [ 'image 1', 'image 3', 'image 2', 'image 5' ]
// => [ 'image 1', 'image 104', 'image 2', 'image 6' ]
// => [ 'image 1', 'image 4', 'image 2', 'image 7' ]
// => [ 'image 1', 'image 3', 'image 2', 'image 5' ]
.as-console-wrapper {max-height: 100% !important; top: 0}
这是动态终止的更新版本
const myData = { contents: [{ name: 'image 1', type: 'file' }, { name: 'playlist 1', type: 'playlist', level: 1, contents: [{ name: 'image 3', type: 'file' }, { name: 'playlist 101', type: 'playlist', level: 2, contents: [{ name: 'image 101', type: 'file' }, { name: 'image 102', type: 'file' }, { name: 'image 103', type: 'file' }, { name: 'image 104', type: 'file' }] }, { name: 'image 4', type: 'file' }] }, { name: 'image 2', type: 'file' }, { name: 'playlist 2', type: 'playlist', level: 1, contents: [{ name: 'image 5', type: 'file' }, { name: 'image 6', type: 'file' }, { name: 'image 7', type: 'file' }] }] };
const iterate = (data) => {
const state = { idx: -1 };
const progress = { cur: 0, max: 0 };
const next = (curData, curState) => {
if (curData.type === 'file') {
return curData.name;
}
const length = curData.contents.length;
if (!('contents' in curState)) {
curState.contents = Array.from({ length }, () => ({ idx: -1 }));
progress.max += length;
}
if (curState.idx === length - 1) {
progress.cur -= curState.idx;
curState.idx = 0;
} else {
progress.cur += 1;
curState.idx += 1;
}
return next(curData.contents[curState.idx], curState.contents[curState.idx]);
};
const nextBatch = () => Array.from(
{ length: data.contents.length },
() => next(data, state)
);
const result = [];
do {
result.push(nextBatch());
} while (progress.cur !== progress.max);
return result;
};
console.log(iterate(myData));
/* => [
[ 'image 1', 'image 3', 'image 2', 'image 5' ],
[ 'image 1', 'image 101', 'image 2', 'image 6' ],
[ 'image 1', 'image 4', 'image 2', 'image 7' ],
[ 'image 1', 'image 3', 'image 2', 'image 5' ],
[ 'image 1', 'image 102', 'image 2', 'image 6' ],
[ 'image 1', 'image 4', 'image 2', 'image 7' ],
[ 'image 1', 'image 3', 'image 2', 'image 5' ],
[ 'image 1', 'image 103', 'image 2', 'image 6' ],
[ 'image 1', 'image 4', 'image 2', 'image 7' ],
[ 'image 1', 'image 3', 'image 2', 'image 5' ],
[ 'image 1', 'image 104', 'image 2', 'image 6' ],
[ 'image 1', 'image 4', 'image 2', 'image 7' ]
] */
.as-console-wrapper {max-height: 100% !important; top: 0}
如果不type
存在file
,这可能会严重崩溃。
推荐阅读
- java - JavaParser:如何从 MethodDeclaration 中检索所有 ParentNode 名称?
- azure - Visual Studio 2019 预览版中的逻辑应用和函数应用开发
- php - 我的 ajax 在循环调用 php 文件时花费了太多时间
- javascript - 如何在游戏循环中只检测一次碰撞而不是连续检测碰撞?
- image - Flutter Row:动态高度和垂直拉伸
- php - 简单的触发错误?!PL/SQL:ORA-00933:
- go - 使用 testcontainer-go 时遇到问题
- ruby-on-rails - 如何使用 ransak 过滤枚举
- architecture - 薄厚原生应用的“参考架构”指南
- php - 基本 Laravel 作业抛出:“不允许序列化‘闭包’”失败