【问题标题】:split HashMap into equal chunks将 HashMap 拆分为相等的块
【发布时间】:2015-06-24 13:54:09
【问题描述】:

HashMap 分成相等的块的最佳方法是什么?例如,这就是我拆分Vec<String> 的方式:

extern crate num_cpus;

fn main() {

    let cpu_count = num_cpus::get();

    let list: Vec<String> = vec!["one".into(), "two".into(), "three".into(), "four".into(), "five".into(), "six".into(), "seven".into(), "eight".into(), "nine".into(), "ten".into()];

    let chunk_len = (list.len() / cpu_count) as usize + 1;
    let mut chunks = Vec::new();
    for chunk in list.chunks(chunk_len) {
        chunks.push(chunk.to_owned());
    }

    for chunk in chunks {
        println!("{:?}", chunk);
    }

}

产生输出

["one", "two"]
["three", "four"]
["five", "six"]
["seven", "eight"]
["nine", "ten"]

我如何对HashMap&lt;String, String&gt; 做同样的事情?

【问题讨论】:

    标签: rust


    【解决方案1】:

    我不确定直接“分块”HashMap 是否有意义。无论如何,解决方案是显而易见的:不要。您可以分块 Vec(实际上是任何数组切片),所以就使用它!毕竟,HashMap 在逻辑上只是 (Key, Value) 对的无序序列。

    fn chunk_vec() {
        let cpu_count = 6 /*num_cpus::get()*/;
    
        let list: Vec<String> = [
            "one", "two", "three", "four", "five",
            "six", "seven", "eight", "nine", "ten"
        ].iter().map(|&s| s.into()).collect();
    
        let chunk_len = (list.len() / cpu_count) as usize + 1;
        let chunks: Vec<Vec<_>> = list.chunks(chunk_len)
            .map(|c| c.iter().collect())
            .collect();
        for chunk in chunks {
            println!("{:?}", chunk);
        }
    }
    
    fn chunk_hash() {
        use std::collections::HashMap;
    
        let cpu_count = 6 /*num_cpus::get()*/;
    
        let hash: HashMap<String, i32> = [
            ("one", 1), ("two", 2), ("three", 3), ("four", 4), ("five", 5),
            ("six", 6), ("seven", 7), ("eight", 8), ("nine", 9), ("ten", 10)
        ].iter().map(|&(k, v)| (k.into(), v)).collect();
    
        let list: Vec<_> = hash.into_iter().collect();
    
        let chunk_len = (list.len() / cpu_count) as usize + 1;
        let chunks: Vec<HashMap<_, _>> = list.chunks(chunk_len)
            .map(|c| c.iter().cloned().collect())
            .collect();
        for chunk in chunks {
            println!("{:?}", chunk);
        }
    }
    

    我冒昧地修改了您的示例代码,以突出两个函数之间的相似之处(和不同之处)。

    【讨论】:

    • 谢谢。不过我很好奇一件事,你为什么使用hash.into_iter() 而不是hash.iter()。我只是想对我的实际情况进行多线程处理,编译器用does not live long enough 杀死了我,直到我将iter() 更改为into_iter()
    • @Caballero: into_iter() 消费主题,获取其内容的所有权。 iter() 只是借用主题及其内容。更直接的原因是iter() 产生一个&amp;(String, i32)s 序列,而into_iter() 产生一个(String, i32)s 序列;注意没有借!这减少了我可能需要做的间接和克隆级别。
    【解决方案2】:

    只要您不关心从HashMap 中取出的元素的顺序,您可以通过调用your_map.into_iter().collect::&lt;Vec&lt;_&gt;&gt;() 将您的HashMap&lt;String, String&gt; 转换为Vec&lt;(String, String)&gt;

    然后你可以使用你用来转换Vec&lt;String&gt;的相同算法


    为了能够与@DK. 的详尽答案竞争,我决定创建一个通用版本的分块算法:

    fn chunk<T, U>(data: U) -> Vec<U>
        where U: IntoIterator<Item=T>,
        U: FromIterator<T>,
        <U as IntoIterator>::IntoIter: ExactSizeIterator
    {
        let cpu_count = 6 /*num_cpus::get()*/;
    
        let mut iter = data.into_iter();
        let iter = iter.by_ref();
    
        let chunk_len = (iter.len() / cpu_count) as usize + 1;
    
        let mut chunks = Vec::new();
        for _ in 0..cpu_count {
            chunks.push(iter.take(chunk_len).collect())
        }
        chunks
    }
    

    PlayPen试试吧

    【讨论】:

    • 六秒。不过,我的更长。 :P
    • 我也在想同样的事情
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多