首页 > 解决方案 > Sort HashMap data by keys

问题描述

Cross referencing to Rust forum, I'm generating a HashMap as in this playground / below code. How can I sort the generated result map based on the keys, in my case based on Dimension, Location:

use std::collections::HashMap;

#[derive(Debug, Eq, PartialEq, Hash, Clone)]
struct Dimension {
    item: String,
    color: String,
    size: String,
    part_number: String
}

#[derive(Debug)]
struct Delivery {
    variant: Dimension,
    location: String,
    quantity: i32,
}

pub fn main() {
    let data = vec![
        Delivery {
            variant: Dimension {item: String::from("A"),
                                color: String::from("B"),
                                size: String::from("C"),
                                part_number: String::from("D")},
            location: String::from("L"),
            quantity: 10,
        },
        Delivery {
            variant: Dimension {item: String::from("A"),
                                color: String::from("B"),
                                size: String::from("C"),
                                part_number: String::from("D")},
            location: String::from("L2"),
            quantity: 3,
        },        
        Delivery {
            variant: Dimension {item: String::from("A"),
                                color: String::from("B"),
                                size: String::from("C"),
                                part_number: String::from("D1")},
            location: String::from("L"),
            quantity: 5,
        }, 
        Delivery {
            variant: Dimension {item: String::from("A"),
                                color: String::from("B"),
                                size: String::from("C"),
                                part_number: String::from("D")},
            location: String::from("L"),
            quantity: 5,
        },        
    ];

    // The keys of this map will be groups
    let mut map: HashMap<(Dimension, String), Delivery> = HashMap::new();
    for d in data {
        let record = map
            .entry((d.variant.clone(), d.location.clone()))
            .or_insert(Delivery {
                variant: d.variant.clone(),
                location: d.location.clone(),
                quantity: 0,
            });
        record.quantity += d.quantity;
    }

    for (variant, delivery) in &map {
        println!("{:?} has {:?}", variant, delivery.quantity);
    }

}

标签: rust

解决方案


The itertools crate extends the standard iterator so that it can be sorted:

use std::collections::HashMap;
use itertools::Itertools;  // itertools = "0.8"

#[derive(Debug, Eq, PartialEq, Hash, Clone, Ord, PartialOrd)]
struct Dimension {
    item: String,
    color: String,
    size: String,
    part_number: String,
}

fn main() {
    // ...

    for key in map.keys().sorted() {
        println!("{:?} has {:?}", key, map[key].quantity);
    }
}

Alternatively, you can use BTreeMap, which is a sorted map by itself:

use std::collections::BTreeMap;

#[derive(Debug, Eq, PartialEq, Hash, Clone, Ord, PartialOrd)]
struct Dimension {
    item: String,
    color: String,
    size: String,
    part_number: String
}

fn main() {
    // ...

    let mut map = BTreeMap::new();
    for d in data {
        let record = map
            .entry((d.variant.clone(), d.location.clone()))
            .or_insert(Delivery {
                variant: d.variant.clone(),
                location: d.location.clone(),
                quantity: 0,
            });
        record.quantity += d.quantity;
    }

    for (variant, delivery) in &map {
        println!("{:?} has {:?}", variant, delivery.quantity);
    }
}

推荐阅读