2017-08-21 59 views
4

我要的是这样的方法:我怎样才能从锈蚀的Vec中获取物品?

fn take<T>(vec: Vec<T>, index: usize) -> Option<T> 

但是,我无法找到这样的方法。我错过了什么吗?或者是否有一个原因实际上是不安全/不能正确完成的。

编辑:这是从​​3210 有不同的问题的目标是一个remove方法并没有慌乱的越界进入这里,我找的是消耗的方法(即,而不是返回的结果。) Vec,并返回其中一个元素。上述问题的答案都没有解决我的问题。

编辑2:为了进一步澄清,我正在寻找的是消耗的VEC,并返回一个元素的方法,无需恢复VEC的不变量的方式removeswap_remove做的开销。

+0

你是指''选项'而不是'选项<&T>',你可以从'vec.get(index)'得到,或者你错过'.get'存在吗? – loganfsmyth

+0

@loganfsmyth我特意指'选项'就像我在问题中说的那样。我想要的是类似于'option.take()'如果这是有道理的? – Others

+0

注意:如果您发现自己定期抛出“Vec”,则可能需要查看是否可以避免实现它们。不管做什么都比做某事快,无论你做得多高效。 –

回答

7

你可以写你的函数是这样的:

fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> { 
    if vec.get(index).is_none() { 
     None 
    } else { 
     Some(vec.swap_remove(index)) 
    } 
} 

这是保证O(1)。


要使用迭代器提另一种解决方案:

fn take<T>(vec: Vec<T>, index: usize) -> Option<T> { 
    vec.into_iter().nth(index) 
} 

我正要写:

虽然Iterator::nth()通常是线性时间操作,迭代器上的矢量重写此方法使其成为O(1)操作。

但后来我注意到,这只是迭代器迭代片。将在上面的代码中使用的std::vec::IntoIter迭代器不会覆盖nth()。它已被尝试here,但它似乎并不那么容易。

所以:截至目前,上面的代码是O(n)操作!

+0

啊,这是一个难看的解决方案,但我认为它应该工作!我仍然认为在Vec上采取'take'方法会很好... – Others

+0

@其他也许你应该打开一个RFC – Boiethios

+0

如何在第一个解决方案中将'mut vec:Vec '更改为'vec:&mut Vec '? – lukwol

1

标准库中不存在fn take<T>(vec: Vec<T>, index: usize) -> Option<T>的原因,是它一般不是很有用。例如,假设你有一个长度为10的Vec<String>,这意味着扔掉9个字符串,只使用1。这看起来很浪费。

通常,标准库将尝试提供在最大场景中有用的API,在这种情况下,拥有fn take<T>(vec: &mut Vec<T>, index: usize) -> Option<T>会更合乎逻辑。

唯一的问题是如何保持不变,当然:

  • 可以通过最后一个元素,这是什么Vec::swap_remove做交换被保留,
  • 它可以通过改变被保留后继元素,这是Vec::drain做什么。

这些非常灵活,可以适应更多特定场景,比如你的。


适应swap_remove

fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> { 
    if index < vec.len() { 
     Some(vec.swap_remove(index)) 
    } else { 
     None 
    } 
} 

适应drain

fn take<T>(mut vec: Vec<T>, index: usize) -> Option<T> { 
    if index < vec.len() { 
     vec.drain(index..index+1).next() 
    } else { 
     None 
    } 
} 

注意到,前者是更有效的:它的O(1)。


为了进一步澄清,我正在寻找消耗的Vec,并返回一个元素的方法,无需恢复Vec的不变量的方式removeswap_remove做的开销。

这对我来说过早的微观优化。

首先,请注意,有必要销毁向量的元素;您可以通过两种方式实现:

  1. swap_remove,然后每个元素遍历消灭他们,
  2. 遍历每个元素来消灭它们,跳过特定index

我不清楚后者会比前者快;如果有任何事情看起来更复杂,更多的分支(我建议两个循环),这可能会甩掉预测器,并且可能不太适合矢量化。

其次,在抱怨恢复Vec的不变量的开销之前,你有没有正确的配置文件的解决方案?

如果我们看一下swap_remove变型中,有3个步骤:

  1. swap_remove(O(1)),
  2. 破坏每个剩余元素(O(N)),
  3. 自由的后备记忆。

步骤2可以被优化了,如果元素没有Drop实施,但除此之外,我会它是一个抛是否(2)或(3)占主导的成本。

TL; DR:恐怕你在拼鬼的问题,配置文件试图优化之前。

+0

我不一定只抱怨恢复Vec不变量的开销(尽管我正在使用的代码是在一个紧密的内部循环中,所以速度对我来说真的很重要),我也想编写代码,意思。在这种情况下,我真的想表达'take'操作,而不是'remove'操作。即使这只是一个速度问题,我仍然需要一个替代方案来反正。 – Others

+0

@其他:“紧内环”和“滴'vec'”听起来不太好。一旦你写了代码,我鼓励你把它发布到代码评论或reddit,并询问如何优化它;希望有一种方法可以避免内部循环中的内存释放,因为这些代码是昂贵的。 –