问题描述
以下是this answer中一个相关问题的摘要:
const data = [
1,2,3,4,5,6,7,8,9,1,0
]
function divide(data,size) {
const result = []
for (let i = 0; i < data.length; i += size) {
const chunk = data.slice(i,i + size);
result.push(chunk)
}
if (result.length > size) {
return divide(result,size)
}
return result;
}
const result = divide(data,5);
console.log(result)
data
数组只是一个整数数组。但是,当您通过divide
运行它时,它会生成一个嵌套数组树,其中每个数组最大为size
。在“已编译”数组的树形版本中,如何说“给我42号商品”?例如,我想在这里使用这个 2 值,即数字42(索引41),如果这是树的样子,则为:
[ ]
[ ],[ ],[ ]
[ ],[ ],[ ] [ ],[ ]
1 6 1 6 1 6 1 6 1 6 1 6 1 6 1 6 1 6 1 6
2 7 2 7 2 7 2 7 (2) 7 2 7 2 7 2 7 2 7 2 7
3 8 3 8 3 8 3 8 3 8 3 8 3 8 3 8 3 8 3 8
4 9 4 9 4 9 4 9 4 9 4 9 4 9 4 9 4 9 4 9
5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0
它的路径是[0,1]
。给定数组中的索引41,如何快速最佳地获取此路径?给定上面的divide
函数以及将数组任意分块为不同大小的容器,一般方程是什么?
根据@Quade的回答,这是迄今为止我最好的开始:
let i = 42
let s = 5
let d = 3
let x = 0
let v = new Array(d)
while (d) {
if (i < s ** d) {
v[x] = 0
} else {
v[x] = Math.floor(i / (s ** d))
}
d--
x++
}
解决方法
基本上,路径是以基数size
表示的索引,其中基数是除法的最大数组大小。例如,以5为底的41是131。因此[1、3、1]。我认为您错误地为此前缀加上了0(只需在代码段中尝试console.log(result[1][3][1])
)即可。
现在,对于较低的索引,您将需要预填充一个或多个零,以便给定树的路径长度始终相同。您需要的位数取决于树的深度,该深度由数据中的最大索引确定。在您的示例中,数据的大小为100,因此最大索引为99。以5为底的99仍为3位数字。因此,在这种情况下,任何路径都应包含3位数字。
关于您的实现的评论
当数据大小小于块大小时,divide
函数当前无法产生正确的结果。在这种情况下,它应该只返回原始数组,但是您的代码仍然将其包装在另一个数组中。
解决方法是在开始时进行大小检查:
if (data.length <= size) return data;
实施
// Get path. Note that the actual tree is not needed; just the data size and chunk size
function getPath(chunkSize,dataSize,index) {
if (index >= dataSize) throw new Error("index out of range");
// Take logarithm,base chunkSize,from the highest possible index (i.e. dataSize - 1)
let depth = Math.floor(Math.log(dataSize - 1) / Math.log(chunkSize)) + 1;
let path = [];
for (let i = 0; i < depth; i++) {
// get each "digit" of the index when represented in base-chunkSize
path.push(index % chunkSize);
index = Math.floor(index / chunkSize);
}
return path.reverse();
}
let path = getPath(5,100,41);
console.log("path",path);
// Create the tree and extract that number at that index:
const data = [
1,2,3,4,5,6,7,8,9,1,0
]
// I moved the base case detection first,so it works correctly
// for trees that are just the original array.
function divide(data,size) {
if (data.length <= size) return data;
const result = [];
for (let i = 0; i < data.length; i += size) {
result.push(data.slice(i,i + size))
}
return divide(result,size);
}
const tree = divide(data,5);
// Now get the value using the path we got
let drill = tree;
while (path.length) {
drill = drill[path.shift()];
}
console.log("value at path",drill);
,
我将给出一个运行该示例的算法,然后让您编写一般形式。设max = 5和element = 42nd
这是一种回想,在每个递归步骤中都向下移动了一层。您的每个步骤都位于42所属的高级数组中。
从顶层数组开始。它可以包含125 = 5x5x5的元素数量(以概括max ^ number_of_sub_layers个)。 42小于125,因此包含在此数组中。您有结果[0]的前0个
现在要知道下一步将进入哪个子层,您可以计算42 // 25(25 = 5x5是每个子数组可以包含的元素数)。您得到42 // 25 = 1,所以42在第二个数组(索引为1)中,现在为[0,1]。
现在,您对第二个数组执行相同的操作。但是数字为42%25 = 17,因为第一个数组中包含25个元素。您计算17 // 5(5是每个子数组包含的元素数)。您得到17 // 5 = 3,因此42将在该数组的第四个子数组中(索引3)。所以现在你有[0,1,3]
然后,当您到达最后一层的数组时,该元素将处于17%5 =第二个位置。
更新
由于我对javascript不太熟悉,这是我在python中的处理方式。代码可以更简洁,但是可以完成工作。
result = []
nblayers = 3 # can be easily computed given your input array data,I let you do it
def compute(array,size,element,depth):
"""
size plays the role of 5 in the example
element plays the role of 42
depth starts with 0 in the top layer array and increments by 1 each level.
"""
nbElements = size ** (nblayers - depth) # max Number of elements that the array can contain
nbChildElements = size ** (nblayers - depth - 1) # max number of elements each sub array can contain
if element > nbElements: # element index is not in the list
return False
if depth == nblayers - 1: # if we are at the leaf array
if element < len(array):
result.append(element)
return True
else:
return False # this can happen only for the last subarray,because only it can contain fewer elements
else:
childArray = element // nbChildElements # child array in which this element will appear
result.append(childArray)
return compute(array[childArray],(element%nbChildElements),depth+1)
#here is you call the function with your inputs
compute(data,42,0)
更新2 关于Python运算符和函数:
- **:就是力量
- []:是一个空列表
- len(list):返回列表的长度
- //:整数除法。例如:5 // 3 = 1
- %:是模运算。例如:5%3 = 2
- list.append(element):将
element
添加到列表list
- array [index]:返回
index
的索引array
处的元素
您可以将所需的索引转换为带有基数的字符串,并以最大长度的最大值填充字符串。
此方法适用于基础,直到10
。
const
getPath = (value,max,base) => value
.toString(base)
.padStart(max.toString(base).length,0)
.split('');
console.log(getPath(41,99,5))
要获得更大的基数,直到36
,您都需要添加一个映射以获得数字。
const
getPath = (value,base) => Array.from(
value.toString(base).padStart(max.toString(base).length,0),v => parseInt(v,base)
);
console.log(getPath(255,255,16))