{"ScriptPreparationCode":"const DATA = {\r\n color: [\u0027red\u0027, \u0027blue\u0027, \u0027green\u0027, \u0027yellow\u0027],\r\n shape: [\u0027circle\u0027, \u0027square\u0027, \u0027triangle\u0027],\r\n location: [\u0027Seattle\u0027, \u0027New York\u0027, \u0027Chicago\u0027, \u0027Los Angeles\u0027, \u0027Portland\u0027],\r\n};\r\n\r\nfunction isGroupable(key) {\r\n return key === \u0027color\u0027 || key === \u0027shape\u0027 || key === \u0027location\u0027;\r\n}\r\n\r\nfunction _randWord(array) {\r\n const index = Math.floor(Math.random() * array.length);\r\n return array[index];\r\n}\r\n\r\nfunction createListItems(count, startIndex = 0) {\r\n return [...Array(count)].map((item, index) =\u003E {\r\n const size = 150 \u002B Math.round(Math.random() * 100);\r\n\r\n const color = _randWord(DATA.color);\r\n const shape = _randWord(DATA.shape);\r\n const location = _randWord(DATA.location);\r\n\r\n return {\r\n thumbnail: \u0060//via.placeholder.com/${size}x${size}\u0060,\r\n key: \u0027item-\u0027 \u002B (index \u002B startIndex),\r\n name: location \u002B \u0027 \u0027 \u002B color \u002B \u0027 \u0027 \u002B shape,\r\n description: 10 \u002B Math.round(Math.random() * 50),\r\n color,\r\n shape,\r\n location,\r\n width: size,\r\n height: size,\r\n };\r\n });\r\n}\r\n\r\nfunction createGroups(\r\n groupCount,\r\n groupDepth,\r\n startIndex,\r\n itemsPerGroup,\r\n level = 0,\r\n key = \u0027\u0027,\r\n isCollapsed,\r\n) {\r\n if (key !== \u0027\u0027) {\r\n key = key \u002B \u0027-\u0027;\r\n }\r\n const count = Math.pow(itemsPerGroup, groupDepth);\r\n return [...Array(groupCount)].map((value, index) =\u003E {\r\n return {\r\n count: count,\r\n key: \u0027group\u0027 \u002B key \u002B index,\r\n name: \u0027group \u0027 \u002B key \u002B index,\r\n startIndex: index * count \u002B startIndex,\r\n level: level,\r\n isCollapsed: isCollapsed,\r\n children: groupDepth \u003E 1 ?\r\n createGroups(groupCount, groupDepth - 1, index * count \u002B startIndex, itemsPerGroup, level \u002B 1, key \u002B index) :\r\n [],\r\n };\r\n });\r\n}\r\n\r\nlet cacheIndex = 0;\r\nconst getObject = (cache, group, groupId, item, itemIndex, type) =\u003E {\r\n const obj = cache[cacheIndex\u002B\u002B];\r\n if (obj) {\r\n // console.log(\u0022cache hit\u0022);\r\n obj.group = group;\r\n obj.groupId = groupId;\r\n obj.item = item;\r\n obj.itemIndex = itemIndex;\r\n obj.type = type;\r\n return obj;\r\n }\r\n\r\n // console.log(\u0022cache miss\u0022)\r\n return {\r\n group,\r\n groupId,\r\n item,\r\n itemIndex,\r\n type\r\n };\r\n}\r\n\r\nfunction flattenItems(groups, items, prevItems, groupProps, useCache = true) {\r\n if (!groups) {\r\n return items;\r\n }\r\n\r\n cacheIndex = 0;\r\n const estimatedNewLength = prevItems.length \u003E 0 ? prevItems.length : items.length;\r\n const nextItems = new Array(estimatedNewLength);\r\n // const nextItems = [];\r\n\r\n // if (memoItems.length \u003C 1) {\r\n // // Not the exact final size but gets us in the ballpark.\r\n // // This helps avoid trashing memory when building\r\n // // the flattened list.\r\n // memoItems = new Array(items.length);\r\n // }\r\n\r\n let index = 0;\r\n // let prevIndex = 0;\r\n\r\n const stack = [];\r\n let j = groups.length - 1;\r\n while (j \u003E= 0) {\r\n stack.push(groups[j]);\r\n j--;\r\n }\r\n\r\n while (stack.length \u003E 0) {\r\n let group = stack.pop();\r\n\r\n\r\n if (useCache) {\r\n nextItems[index] = getObject(prevItems, group, \u0027GroupedListSection\u0027 \u002B index, undefined, undefined, \u0027group\u0027);\r\n } else {\r\n nextItems[index] = {\r\n group,\r\n groupId: \u0027GroupedListSection\u0027 \u002B index,\r\n type: \u0027group\u0027,\r\n };\r\n }\r\n index\u002B\u002B;\r\n\r\n while (group.isCollapsed !== true \u0026\u0026 group?.children \u0026\u0026 group.children.length \u003E 0) {\r\n j = group.children.length - 1;\r\n while (j \u003E 0) {\r\n stack.push(group.children[j]);\r\n j--;\r\n }\r\n group = group.children[0];\r\n if (useCache) {\r\n nextItems[index] = getObject(prevItems, group, \u0027GroupedListSection\u0027 \u002B index, undefined, undefined, \u0027group\u0027);\r\n } else {\r\n nextItems[index] = {\r\n group,\r\n groupId: \u0027GroupedListSection\u0027 \u002B index,\r\n type: \u0027group\u0027,\r\n };\r\n }\r\n index\u002B\u002B;\r\n }\r\n\r\n if (group.isCollapsed !== true) {\r\n let itemIndex = group.startIndex;\r\n const renderCount = groupProps.getGroupItemLimit ? groupProps.getGroupItemLimit(group) : Infinity;\r\n const count = !group.isShowingAll ? group.count : items.length;\r\n const itemEnd = itemIndex \u002B Math.min(count, renderCount);\r\n while (itemIndex \u003C itemEnd) {\r\n if (useCache) {\r\n nextItems[index] = getObject(prevItems, group, undefined, items[itemIndex], itemIndex, \u0027item\u0027);\r\n } else {\r\n nextItems[index] = {\r\n group,\r\n item: items[itemIndex],\r\n itemIndex, // track the index in \u0060item\u0060 for later rendering/selection\r\n type: \u0027item\u0027,\r\n };\r\n }\r\n\r\n\r\n itemIndex\u002B\u002B;\r\n index\u002B\u002B;\r\n }\r\n\r\n const isShowAllVisible = !group.children \u0026\u0026\r\n !group.isCollapsed \u0026\u0026\r\n !group.isShowingAll \u0026\u0026\r\n (group.count \u003E renderCount || group.hasMoreData);\r\n\r\n if (isShowAllVisible) {\r\n if (useCache) {\r\n nextItems[index] = getObject(prevItems, group, undefined, undefined, undefined, \u0027showAll\u0027);\r\n } else {\r\n nextItems[index] = {\r\n group,\r\n type: \u0027showAll\u0027,\r\n };\r\n }\r\n index\u002B\u002B;\r\n }\r\n }\r\n // Placeholder for a potential footer.\r\n // Whether or not a footer is displayed is resolved\r\n // by the footer render function so this is just a marker\r\n // for where a footer may go.\r\n if (useCache) {\r\n nextItems[index] = getObject(prevItems, group, undefined, undefined, undefined, \u0027footer\u0027);\r\n } else {\r\n nextItems[index] = {\r\n group,\r\n type: \u0027footer\u0027,\r\n };\r\n }\r\n index\u002B\u002B;\r\n }\r\n\r\n nextItems.length = index;\r\n\r\n // console.log(\u0027MEMO ITEMS\u0027, memoItems);\r\n\r\n return nextItems;\r\n};\r\n\r\nconst groupCount = 6;\r\nconst groupDepth = 6;\r\n\r\nvar groups = createGroups(groupCount, groupDepth, 0, groupCount)\r\nvar items = createListItems(Math.pow(groupCount, groupDepth \u002B 1));\r\n\r\nvar cached = flattenItems(groups, items, [], {}, false);\r\n","TestCases":[{"Name":"With Cache","Code":"flattenItems(groups, items, [], {});\r\n","IsDeferred":false},{"Name":"Without Cache","Code":"flattenItems(groups, items, cached, {}, false);\r\n","IsDeferred":false}]}