Vector 有没有更有效的方法来调整以矢量表示的二维网格的大小?
我有一个包含由单个Vec表示的二维网格的结构,因为wasm_bindgen不支持要简单地减少分配数量,可以让传递到flat_map的闭包返回迭代器而不是Vec: 也就是说,对于每个块,创建一个迭代器,该迭代器生成块的复制内容,后跟一个0的重复字符串,并将其截断为总大小new_width。这不需要创建任何VEC来存储中间结果,因此它分配的。。。很有可能 这没关系,但可能会更好。FlatMap无法知道内部迭代器的大小,因此它没有给出有用的大小提示(参见类似示例)。这意味着上述解决方案中的Vec开始为空,可能需要重新分配,并复制其内容数次,然后才能足够大。相反,我们可以先使用Vec::with_capacity来保留正确的空间量,并扩展向量而不是将其收集到其中:Vector 有没有更有效的方法来调整以矢量表示的二维网格的大小?,vector,memory-management,rust,Vector,Memory Management,Rust,我有一个包含由单个Vec表示的二维网格的结构,因为wasm_bindgen不支持要简单地减少分配数量,可以让传递到flat_map的闭包返回迭代器而不是Vec: 也就是说,对于每个块,创建一个迭代器,该迭代器生成块的复制内容,后跟一个0的重复字符串,并将其截断为总大小new_width。这不需要创建任何VEC来存储中间结果,因此它分配的。。。很有可能 这没关系,但可能会更好。FlatMap无法知道内部迭代器的大小,因此它没有给出有用的大小提示(参见类似示例)。这意味着上述解决方案中的Vec开始为
pub fn set_width(&mut self, new_width: usize) {
use std::iter::repeat;
let mut new_grid = Vec::with_capacity(self.grid.len() / self.width * new_width);
for chunk in self.grid.chunks_exact(self.width) {
new_grid.extend(chunk.iter().copied().chain(repeat(0)).take(new_width));
}
self.grid = new_grid;
self.width = new_width;
}
也可以就地调整网格的大小,最多一次重新分配通常会重用现有网格。然而,该算法要复杂得多。上面是我编写set_width的方法,除非它被证明是一个瓶颈。要简单地减少分配数量,可以让传递给flat_map的闭包返回迭代器而不是Vec: 也就是说,对于每个块,创建一个迭代器,该迭代器生成块的复制内容,后跟一个0的重复字符串,并将其截断为总大小new_width。这不需要创建任何VEC来存储中间结果,因此它分配的。。。很有可能 这没关系,但可能会更好。FlatMap无法知道内部迭代器的大小,因此它没有给出有用的大小提示(参见类似示例)。这意味着上述解决方案中的Vec开始为空,可能需要重新分配,并复制其内容数次,然后才能足够大。相反,我们可以先使用Vec::with_capacity来保留正确的空间量,并扩展向量而不是将其收集到其中:
pub fn set_width(&mut self, new_width: usize) {
use std::iter::repeat;
let mut new_grid = Vec::with_capacity(self.grid.len() / self.width * new_width);
for chunk in self.grid.chunks_exact(self.width) {
new_grid.extend(chunk.iter().copied().chain(repeat(0)).take(new_width));
}
self.grid = new_grid;
self.width = new_width;
}
也可以就地调整网格的大小,最多一次重新分配通常会重用现有网格。然而,该算法要复杂得多。以上是我将如何编写set_width,除非它被证明是一个瓶颈。网格点的顺序与您相关吗?如果不是,我将使用从2D到1D的不同序列化: 假设你有这样一个矩阵:
1 2 5
3 4 6
7 8 9
因此,如果矩阵变得更宽或更高,则根本不移动较小位置的索引,而是将新条目作为新的“层”附加到已有矩阵周围
您可以将其序列化为[1,2,3,4,5,6,7,8,9]
假设所有索引和坐标从0开始:
如果你想访问n,m,你可以通过计算maxn,m找到矩阵值所在的“层”。第n个“层”将从索引位置n*n开始。在该层中,您可以在右侧添加的零件中找到前n个元素,在底部添加的行中找到以下n+1个元素。网格点的顺序是否与您相关?如果不是,我将使用从2D到1D的不同序列化: 假设你有这样一个矩阵:
1 2 5
3 4 6
7 8 9
因此,如果矩阵变得更宽或更高,则根本不移动较小位置的索引,而是将新条目作为新的“层”附加到已有矩阵周围
您可以将其序列化为[1,2,3,4,5,6,7,8,9]
假设所有索引和坐标从0开始:
如果你想访问n,m,你可以通过计算maxn,m找到矩阵值所在的“层”。第n个“层”将从索引位置n*n开始。在该层中,您可以找到右侧添加的零件中的前n个元素,以及底部添加的行中的以下n+1个元素。尝试调整网格宽度的大小,仅在new_width>self.width时保留一次新内存: 我曾考虑在Vec的反向行上迭代,并使用splice插入/删除值,但我不确定它是否更有效 使用接头:
尝试在适当位置调整网格宽度,仅在new_width>self.width时保留一次新内存: 我曾考虑在Vec的反向行上迭代,并使用splice插入/删除值,但我不确定它是否更有效 使用接头:
我希望能够调整网格的宽度-是否也要调整高度。另一种方法是使用n维数组库。例如:@Shepmaster我现在可以使用self.grid.resizeself.width*new_height调整高度,0可添加或删除Vec末端的行。谢谢你的文章,我得多读一些关于这个话题的文章
!如果可以更改为a,则可以在O1中减小宽度,并将其增加回原来的宽度或更小。O1我希望能够调整网格的宽度-是否也要调整高度。另一种方法是使用n维数组库。例如:@Shepmaster我现在可以使用self.grid.resizeself.width*new_height调整高度,0可添加或删除Vec末端的行。谢谢你的文章,我将不得不阅读更多关于这个主题的文章!如果您可以更改为a,则可以在O1中减小宽度,并将其增加回原来的宽度或更小,这是一个很酷的想法,但它仅支持方形或近似方形矩阵,对吗?@trentcl如果它不是完全正方形,你可以将高度和宽度保留在单独的变量中,忽略你不需要的索引。如果矩阵非常不对称,您可能会修改序列化为其他矩阵的方式。这是一个很酷的想法,但它只支持正方形或近似正方形的矩阵,对吗?@trentcl如果它不完全是正方形,您可以将高度和宽度保留在单独的变量中,忽略不需要的索引。如果矩阵非常不对称,您可能会修改序列化为其他矩阵的方式。
1 2 5
3 4 6
7 8 9
use std::{cmp::Ordering, iter};
pub fn set_width(&mut self, new_width: usize) {
match new_width.cmp(&self.width) {
Ordering::Greater => {
let width_diff = new_width - self.width;
self.grid.reserve_exact(width_diff * self.height);
for _ in 0..self.height {
self.grid.extend(iter::repeat(0).take(width_diff));
self.grid.rotate_right(new_width);
}
}
Ordering::Less => {
let width_diff = self.width - new_width;
for _ in 0..self.height {
self.grid.truncate(self.grid.len() - width_diff);
self.grid.rotate_right(new_width);
}
}
Ordering::Equal => (),
}
self.width = new_width;
}
use std::{cmp::Ordering, iter};
pub fn set_width(&mut self, new_width: usize) {
match new_width.cmp(&self.width) {
Ordering::Greater => {
let width_diff = new_width - self.width;
let width = self.width;
self.grid.reserve_exact(width_diff * self.height);
for i in (0..self.height).rev().map(|n| n * width + width) {
self.grid.splice(i..i, iter::repeat(0).take(width_diff));
}
}
Ordering::Less => {
let width_diff = self.width - new_width;
let width = self.width;
for (start, end) in (1..=self.height)
.rev()
.map(|n| (n * width - width_diff, n * width))
{
self.grid.splice(start..end, iter::empty());
}
}
Ordering::Equal => (),
}
self.width = new_width;
}