2017-03-07 118 views
2

通过使用迭代器将HashMap<String, String>转换为Vec<(String, Vec<String>)>最简单的方法是什么?我想扭转地图。如何使用迭代器将对象映射映射到元组向量?

我试着使用iter()方法,但不知道如何做一个正确的map封闭实施后收集值:

fn get_aliases(&self) -> Vec<(String, Vec<String>)> { 
    let mut aliases: HashMap<String, String> = HashMap::new(); 
    aliases.insert("a".to_owned(), "test".to_owned()); 
    aliases.insert("b".to_owned(), "test".to_owned()); 
    aliases.insert("c".to_owned(), "test2".to_owned()); 

    aliases.iter().map(|(ref a, ref c)| { 
     // what to do here? 
    }).collect() 

    // the expected return value is: 
    // [("test", ["a", "b"]), ("test2", ["c"])] 
} 

该函数将返回该说什么String键属于某一个向量目的。

我可以用forfind s写很多代码,但在我看来这样效率会降低,我认为有一种方法可以通过仅使用迭代器来实现。

+0

是'Object' hashable or'Ord'?我想我会收集到一个映射('HashMap'或'BTreeMap'),其中键/值先交换以合并这些键,然后将其平化为'Vec'。 –

+0

一个简单的例子显示(1)'别名'的内容和(2)所得到的'Vec'的预期内容将会使这个问题变得更容易理解。 –

+0

@MatthieuM。我已经简化了这个问题,我希望现在更清楚。 –

回答

3

我可以写很多代码forfind秒,但在我看来,这将是低效率的,我认为是有办法做到这一点只用迭代器。

我不会把它大量的代码,记住for循环上迭代操作。我没有做任何基准测试,但是这更简单,我期望它更高性能:

use std::collections::HashMap; 

fn get_aliases(aliases: HashMap<String, String>) -> Vec<(String, Vec<String>)> { 
    let mut x = HashMap::new(); 

    for (k, v) in aliases { 
     x.entry(v).or_insert_with(Vec::new).push(k) 
    } 

    x.into_iter().collect() 
} 

fn main() { 
    let mut aliases = HashMap::new(); 
    aliases.insert("a".to_owned(), "test".to_owned()); 
    aliases.insert("b".to_owned(), "test".to_owned()); 
    aliases.insert("c".to_owned(), "test2".to_owned()); 

    println!("{:?}", get_aliases(aliases)); 
} 
2

这不是微不足道的,当然不像其他一些提供必要功能的流库那样微不足道。

您可以使用itertools箱子的group_by按某个键对元素进行分组。但是,它只对相邻的元素进行分组,因此您必须先对它们进行排序。这里是我的结果:

impl A { 
    pub fn get_aliases(&self) -> Vec<(String, Vec<String>)> { 
     // Get a Vec of string references for sorting. Reverse element 
     // order for clarity. 
     let mut v = self.aliases.iter() 
      .map(|(a, c)| (&c[..], &a[..])).collect::<Vec<_>>(); 
     v.sort_by_key(|t| t.0); // Make identical keys adjacent. 
     let g = v.into_iter().group_by(|t| t.0); // Create grouping. 
     g.into_iter() 
      .map(|(key, group)| // key is the str with the key 
           // group is a subiterator that just visits 
           // elements with that key, Item=&(&str,&str) 
       (key.to_string(), // result is a tuple of the key as String 
       group.map(|t| t.1.to_string()).collect()) 
        // and the subiterator turned into a Vec<String> 
       ) 
      .collect() // finally, turn Iterator<Item=(String, Vec<String>) into Vec 
    } 
} 

再回到原来的问题,你有更多的问题,即Arc<Object>只有PartialEq(由group_by需要)如果Object是; Ord(需要sort_by_key)。如果您的Object类型无法以这种方式进行比较,并且您想使用指针标识,那么您的中间向量将需要在Arc周围存储一些使用指针值进行比较的新类型包装。