< 返回版块

ltoddy 发表于 2020-12-19 22:37

如题:

我有这么一个样子的Vec

let array = vec![key1, value1, key2, value2];

想要变成:

let map = hash_map! {
    key1 => value1,
    key2 => value2,
}

使用 array.chunks_exact(2)不行。

评论区

写评论
liyiheng 2020-12-22 10:04

#[macro_export]
macro_rules! hash {
    ($($k:expr , $v:expr);*)=>{
        {
                let mut h = std::collections::HashMap::new();
                $(
                    h.insert($k,$v);
                )*
                h
        }
    };
    ($($k:expr , $v:expr;)*)=>(hash!($($k , $v);*));
}

fn main() {
    let h = hash!("a",1;"b",2;);
    for (k,v) in h.iter(){
        println!("{},{}", k,v);
    }
}

Aya0wind 2020-12-20 09:56

你可以自己封装一个特殊的iter,返回一个二元组来做。或者直接手动遍历,并不怎么麻烦,而且不需要是vec,任何实现了intoiterator的都可以这么转换。

fn seq_to_map<T: IntoIterator>(vec: T) -> HashMap<T::Item, T::Item>
where
    T::Item: Hash + Default + Eq,
{
    let mut map = HashMap::default();
    let mut iter = vec.into_iter();
    while let Some(e) = iter.next() {
        map.entry(e).or_insert(iter.next().unwrap_or_default());
    }
    map
}

这里加了个要求default trait,因为万一你的vec不是偶数个元素,最后一个key没有value,就需要有默认值了,你也可以选择丢弃掉最后这个key,把unwrap_or_default改成unwrap,然后自己保证元素是成对的。

或者作为一个宏,效果一样

macro_rules! seq_to_map {
    ($seq:expr) => {{
        let mut map = HashMap::<_, _, RandomState>::default();
        let mut iter = $seq.into_iter();
        while let Some(e) = iter.next() {
            map.entry(e).or_insert(iter.next().unwrap_or_default());
        }
        map
    }};
}
作者 ltoddy 2020-12-20 07:44

因为HashMap是实现了:FromIterator<Item> trait,其中Item为二元祖(Key, Value). 所以我觉得能通过 .collect::<HashMap<_, _>>() 这样的函数式的方式实现会更优雅一些。

作者 ltoddy 2020-12-20 07:40

今天在研究一下吧,寻找一种优雅的方式。

作者 ltoddy 2020-12-20 07:39

是的,我遍历完array,我就不需要array了。

--
👇
Neutron3529: 如果你想要这个array,但array里面的每个元素只能move,而且你想把这些元素move到HashMap里面,同时你还想保留array仍然有效——这显然是不可能的。

所以,假设你的array不想要了(只保留HashMap,不保留array)

然后开始神奇操作

#[derive(Eq,PartialEq,Hash,Debug)]
struct Noclone(i32);
fn main(){
    let array=vec![Noclone(1),Noclone(2),Noclone(3),Noclone(4)];//你的array,比如这是函数传进来的东西,所有权归你,但默认不可变
    let mut array=array;//改变array的可变性,反正所有权归你
    //let test=array.clone();//用于测试,取消注释可以发现,array的确不存在clone
    let mut m=std::collections::HashMap::new();
    let mut it=array.drain(..);
    while let (Some(x),Some(i))=(it.next(),it.next()){
        m.insert(x,i);
    }
    dbg!(m);//可以看到m变成了你需要的形状
}
作者 ltoddy 2020-12-20 07:38

唔,我一开始理解错了,我以为itertools指的, vec.iter()里面的东西。

--
👇
uno: ```rust use itertools::Itertools; vec.into_iter().tuples().collect::<HashMap<_, _>>();

uno 2020-12-19 23:55
    use itertools::Itertools;
    vec.into_iter().tuples().collect::<HashMap<_, _>>();
Neutron3529 2020-12-19 23:52

如果你想要这个array,但array里面的每个元素只能move,而且你想把这些元素move到HashMap里面,同时你还想保留array仍然有效——这显然是不可能的。

所以,假设你的array不想要了(只保留HashMap,不保留array)

然后开始神奇操作

#[derive(Eq,PartialEq,Hash,Debug)]
struct Noclone(i32);
fn main(){
    let array=vec![Noclone(1),Noclone(2),Noclone(3),Noclone(4)];//你的array,比如这是函数传进来的东西,所有权归你,但默认不可变
    let mut array=array;//改变array的可变性,反正所有权归你
    //let test=array.clone();//用于测试,取消注释可以发现,array的确不存在clone
    let mut m=std::collections::HashMap::new();
    let mut it=array.drain(..);
    while let (Some(x),Some(i))=(it.next(),it.next()){
        m.insert(x,i);
    }
    dbg!(m);//可以看到m变成了你需要的形状
}
作者 ltoddy 2020-12-19 23:30

我的思路是: vec.chunks_exact(2).map(|chunk| (chunk[0], chunk[1])).collect::<HashMap::<_, _>>()

不行,我的Vec结构体里面的元素没有clone,没有copy方法。而且, 我的vec也不是mut的。

--
👇
uno: 看看itertools有没有你要的

uno 2020-12-19 23:24

看看itertools有没有你要的

作者 ltoddy 2020-12-19 23:02

不行,试过了。

--
👇
Mike Tang: for iter 一下不行么?

Mike Tang 2020-12-19 22:56

for iter 一下不行么?

1 共 12 条评论, 1 页