首页 > 解决方案 > 如何使用根节点项按顺序遍历嵌套 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 即获取播放列表返回与示例二匹配的响应

标签: javascriptalgorithmdata-structureslogic

解决方案


这是一个简单的递归解决方案

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,这可能会严重崩溃。


推荐阅读