只需一次查找就可以在HashMap上执行一次“获取”和两次“插入”操作吗?

丹尼尔五世

我有一个需要的应用程序:

  1. 在哈希表中查找值,如果存在则返回
  2. 如果不存在,请存储一个临时值
  3. 使用表中的其他值计算新值
  4. 将新值存储到哈希表中
  5. 返回新值

我只想通过1次哈希/查找来做到这一点。那可能吗?可以用2做吗?


我正在计算斐波那契以表明目的。从3个查找到1个查找进行优化的index()函数是:

// Written by beefucurry

use std::collections::HashMap;

use std::cell::UnsafeCell;

fn main() {
    let fib = SaveCall::<u32, u32>::new(|k, fib_| {
        if k < 2 {
            return k;
        } else {
            return fib_[k - 1] + fib_[k - 2];
        }
    });

    for k in (0..30).rev() {
        println!("fib[{}] = {}", k, fib[k]);
    }
}

pub struct SaveCall<'a, In: std::cmp::Eq + std::hash::Hash + Copy, Out> {
    cache: UnsafeCell<HashMap<In, Option<Out>>>,
    f: Box<dyn Fn(In, &SaveCall<'a, In, Out>) -> Out + 'a>,
}
impl<'a, In: std::cmp::Eq + std::hash::Hash + Copy, Out> SaveCall<'a, In, Out> {
    pub fn new(f: impl Fn(In, &Self) -> Out + 'a) -> Self {
        Self {
            cache: UnsafeCell::new(HashMap::new()),
            f: Box::new(f),
        }
    }
}

impl<'a, In: std::cmp::Eq + std::hash::Hash + Copy, Out> std::ops::Index<In>
    for SaveCall<'a, In, Out>
{
    type Output = Out;
    fn index<'b>(&'b self, input: In) -> &'b Self::Output {
        unsafe {
            //println!("~~Looking up {:?}", input);
            let cache = self.cache.get();
            let saved = (*cache).get(&input);
            if saved.is_some() {
                //println!("~~Found {:?}", input);
                let z = saved.unwrap().as_ref();
                if z.is_some() {
                    return z.unwrap();
                } else {
                    panic!("Attempted to compute a value based on itself");
                }
            }
            (*cache).insert(input, None);
            //println!("~~Computing {:?}", input);
            let output: Out = (self.f)(input, self);
            //println!("~~Writing to cache {:?}", input);
            (*cache).insert(input, Some(output));
            let output_ref = (*cache).get(&input).unwrap().as_ref().unwrap();
            output_ref
        }
    }
}

操场

对数神话

我只想通过1次哈希/查找来做到这一点。那可能吗?

仅凭一次哈希查找是不可能的,因为Rust无法知道计算本身是否可能尝试更改SaveCall对象的结构如果您的回调不接受self作为参数,则有可能,但不能使用所需的API。

可以用2做吗?

可以使用2使用HashMap::entry,它使您可以在地图中搜索键,并修改位置并检查它是否具有值,而不必重新计算哈希。

最初查询表并返回或插入时None可以使用此方法一次计算哈希,然后在获得最终结果时可以正常插入。

这将我们带到您的代码本身。无法使用std::ops::Index特征来做您想要的事情。您的示例代码试图通过解决该问题UnsafeCell,但是您的不安全代码违反了不安全代码必须遵守的要求。

简短的版本是该Index特征返回一个引用。您特别希望通过在访问条目时插入条目来对地图进行变异,这意味着HashMap必须增加并为其值重新分配空间。如果您必须重新分配,这意味着无法返回所返回的引用index,因为它们引用的是已重新分配的内存。

那会留在哪里?

  1. 您需要停止使用Index特征,而应在您的SavedCall类型上实现不返回引用的方法。
  2. 您需要决定要返回什么。如果要Out直接返回,则Out需要显式为一个Copy类型。如果要支持非复制类型,则可能需要返回RcArc

例如

impl<'a, In: std::cmp::Eq + std::hash::Hash + Copy, Out> SaveCall<'a, In, Out> {
    fn get(&self, input: In) -> Rc<Out> {

要么

impl<'a, In: std::cmp::Eq + std::hash::Hash + Copy, Out: Copy> SaveCall<'a, In, Out> {
    fn get(&self, input: In) -> Out {

这是在Rust操场上基于示例代码构建的更完整的版本这使用Rc最好地演示了该示例,但是如果可以的话,可以将其精简Out: Copy

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

插入查询变成两次执行一次

来自分类Dev

如果Python一次执行一次,为什么在声明变量之前就可以看到变量?

来自分类Dev

SQL Server查询执行两次插入而不是一次

来自分类Dev

Microsoft Flow 执行 SQL 操作两次而不是一次

来自分类Dev

PHP脚本被调用两次,等待上一次执行的结束

来自分类Dev

如何获得每次制作一次的食谱(适用于GNU的东西就可以了)

来自分类Dev

通过Swift segue传递数据每隔一次就可以工作

来自分类Dev

jQuery mouseOver淡入两次只需要一次

来自分类Dev

尽管执行了一次检查,但同时执行插入命令会将数据两次写入数据库

来自分类Dev

使用Retrofit2 / okhttp3上传文件,上传操作始终执行两次,一次快速,另一次缓慢

来自分类Dev

save()被调用一次,但是第一次在猫鼬中执行两次

来自分类Dev

由于两次查找而不是一次查找,速度是否变慢?

来自分类Dev

XPages事件代码执行两次,然后执行一次

来自分类Dev

执行方法被延迟,即使在延迟内触发两次,也只能执行一次

来自分类Dev

PHP-仅在执行一次execute()时执行两次PDO查询

来自分类Dev

JComboBox itemStateChanged事件一次调用两次

来自分类Dev

指定一次属性,而不是两次

来自分类Dev

gsub将一次出现替换两次

来自分类Dev

警报显示两次,而不是一次

来自分类Dev

使用netcat一次完成ssh两次

来自分类Dev

StateHasChanged()两次重新渲染一次组件

来自分类Dev

ToggleButton使mediaplayer一次播放两次

来自分类Dev

Javascript运行两次而不是一次

来自分类Dev

压缩文件一次,提取两次

来自分类Dev

MessageBox 显示两次而不是一次

来自分类Dev

Foreach 在一次迭代中重复两次

来自分类Dev

一次运行两次脚本

来自分类Dev

“ git remote -v”显示(获取)和(推送)两次,一次用于“ github”,一次用于“ origin”是什么意思?

来自分类Dev

把手包括部分两次,一次转义一次,一次渲染

Related 相关文章

  1. 1

    插入查询变成两次执行一次

  2. 2

    如果Python一次执行一次,为什么在声明变量之前就可以看到变量?

  3. 3

    SQL Server查询执行两次插入而不是一次

  4. 4

    Microsoft Flow 执行 SQL 操作两次而不是一次

  5. 5

    PHP脚本被调用两次,等待上一次执行的结束

  6. 6

    如何获得每次制作一次的食谱(适用于GNU的东西就可以了)

  7. 7

    通过Swift segue传递数据每隔一次就可以工作

  8. 8

    jQuery mouseOver淡入两次只需要一次

  9. 9

    尽管执行了一次检查,但同时执行插入命令会将数据两次写入数据库

  10. 10

    使用Retrofit2 / okhttp3上传文件,上传操作始终执行两次,一次快速,另一次缓慢

  11. 11

    save()被调用一次,但是第一次在猫鼬中执行两次

  12. 12

    由于两次查找而不是一次查找,速度是否变慢?

  13. 13

    XPages事件代码执行两次,然后执行一次

  14. 14

    执行方法被延迟,即使在延迟内触发两次,也只能执行一次

  15. 15

    PHP-仅在执行一次execute()时执行两次PDO查询

  16. 16

    JComboBox itemStateChanged事件一次调用两次

  17. 17

    指定一次属性,而不是两次

  18. 18

    gsub将一次出现替换两次

  19. 19

    警报显示两次,而不是一次

  20. 20

    使用netcat一次完成ssh两次

  21. 21

    StateHasChanged()两次重新渲染一次组件

  22. 22

    ToggleButton使mediaplayer一次播放两次

  23. 23

    Javascript运行两次而不是一次

  24. 24

    压缩文件一次,提取两次

  25. 25

    MessageBox 显示两次而不是一次

  26. 26

    Foreach 在一次迭代中重复两次

  27. 27

    一次运行两次脚本

  28. 28

    “ git remote -v”显示(获取)和(推送)两次,一次用于“ github”,一次用于“ origin”是什么意思?

  29. 29

    把手包括部分两次,一次转义一次,一次渲染

热门标签

归档