注意:How to get subslices已关闭,但没有约束。
我正在寻找具有此签名的函数的最佳实现:
Nmap done: 1 IP address (1 host up)...
与Nmap done: 1 IP address (0 hosts up)...
具有相同的功能,但用>>> X = np.ones((3, 6))
>>> Y = np.ones((6, 3)) * 2
>>> Z1 = np.zeros((6,6))
>>> Z2 = np.zeros((3,3))
>>>
>>> np.vstack((Z1, X))
array([[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1., 1.]])
>>> np.vstack((Y, Z2))
array([[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
>>> np.hstack((np.vstack((Z1, X)), np.vstack((Y, Z2))))
array([[ 0., 0., 0., 0., 0., 0., 2., 2., 2.],
[ 0., 0., 0., 0., 0., 0., 2., 2., 2.],
[ 0., 0., 0., 0., 0., 0., 2., 2., 2.],
[ 0., 0., 0., 0., 0., 0., 2., 2., 2.],
[ 0., 0., 0., 0., 0., 0., 2., 2., 2.],
[ 0., 0., 0., 0., 0., 0., 2., 2., 2.],
[ 1., 1., 1., 1., 1., 1., 0., 0., 0.],
[ 1., 1., 1., 1., 1., 1., 0., 0., 0.],
[ 1., 1., 1., 1., 1., 1., 0., 0., 0.]])
替换失败案例而不是恐慌。
扭曲是看似不寻常的约束,这个功能不应该:
fn sub(slice: &[u8], range: Range<usize>) -> Option<&[u8]>;
impl Index<Range<usize>>
代码对slice
界面的仔细调查引起了我的注意:
split_first
和split_last
split_at
None
(和变体)as_ptr
和from_raw_parts
但大多数都不合适:
panic
和unsafe
可能会恐慌impl Index<Range<usize>>
是split_at
请允许我将Index<Range<usize>>::index
实施为:
from_raw_parts
虽然看起来工作有O(N)的复杂性;相当不满意。
有没有办法做得更好?
答案 0 :(得分:6)
我将从我喜欢的版本开始。它是get_slice
,它使用边界检查切片,您可以查看编译器的优化输出,以验证编译器是否知道它永远不会发生混乱。 ( 1。我同意,“没有恐慌”是一个很好的事情,能够作为一个断言工作; 2 .get_slice将是libstd的一个很好的补充和确实是有计划的。)
/// Return the subslice corresponding to `range`, if it is in bounds
/// and well formed (start <= end).
pub fn get_slice(slice: &[u8], range: Range<usize>) -> Option<&[u8]> {
if range.start > range.end || range.end > slice.len() {
None
} else {
Some(&slice[range])
}
}
接下来是一个尝试的解决方案,仍然使用似乎是 O(N)算法编码,但强度降低到 O(1)优化
我们使用切片迭代器以及我们可以将其转换回切片的事实。切片迭代器的.nth()
被打开编码以在恒定时间内向前跳转,但遗憾的是反向版本没有。然而,它的循环已经过优化。
pub fn sub(slice: &[u8], range: Range<usize>) -> Option<&[u8]> {
if range.start > range.end || range.end > slice.len() {
return None;
}
let mut iter = slice.iter();
let take_front = range.start;
let take_back = slice.len() - range.end;
if take_front > 0 {
iter.nth(take_front - 1);
}
if take_back > 0 {
(&mut iter).rev().nth(take_back - 1);
}
Some(iter.as_slice())
}
注意:遗憾的是我认为我们在这里做了一些武断的规则。我们可以在take front操作之后使用.chunks()
,它会为您提供直接的 O(1)解决方案。但是,如果要求0大小的块,块可能会出现混乱。这只是在我使用边界检查切片时将它放在同一个括号中(“它可能会引起恐慌”)。
答案 1 :(得分:2)
现在,您只需在切片上使用get
方法即可。
我从The document of that method复制了以下代码。
let v = [10, 40, 30];
assert_eq!(Some(&40), v.get(1));
assert_eq!(Some(&[10, 40][..]), v.get(0..2));
assert_eq!(None, v.get(3));
assert_eq!(None, v.get(0..4));