Как собрать справочные значения из хэш-карты?

Я написал фрагмент кода для использования HashMap<String, Vec<&String>> в качестве основной структуры данных, и, наконец, я хочу вернуть собранный Vec<Vec<String>>, Я могу заархивировать его с помощью цикла for, есть ли способ сделать это с помощью чистого итератора? (Я пробовал несколько раз, но получил массу запутанных ошибок компилятора)

pub fn group_anagrams(strs: Vec<String>) -> Vec<Vec<String>> {
    let mut map: HashMap<String, Vec<&String>> = HashMap::new();
    for s in &strs {
        let mut key = s.clone();
        unsafe {
            key.as_bytes_mut().sort();
        }
        (*map.entry(key).or_insert(vec![])).push(s);
    }
    let mut ans: Vec<Vec<String>> = Vec::new();
    // I don't like these 2 lines
    for v in map.values() {
        ans.push(v.iter().cloned().cloned().collect::<Vec<String>>())
    }
    ans
}

Я также пробовал с этим кодом:

    pub fn group_anagrams(strs: Vec<String>) -> Vec<Vec<String>> {
        let mut map: HashMap<String, Vec<String>> = HashMap::new();
        for s in strs {
            let mut key = s.clone();
            unsafe {
                key.as_bytes_mut().sort();
            }
            (*map.entry(key).or_insert(vec![])).push(s);
        }
        map.values().cloned().collect::<Vec<Vec<String>>>()
    }

В последней строке я хочу переместить все значения из hashmap в результирующий вектор, но также не удалось из-за ошибки времени жизни (тогда я отказался от клонированного вектора), мне интересно, как это сделать.

1 ответ
1

    unsafe {
        key.as_bytes_mut().sort();
    }

Это работает, пока вы работаете в Ascii, но будет иметь неопределенное поведение, если в строке есть какой-либо юникод.

 (*map.entry(key).or_insert(vec![])).push(s);

Вам не нужно разыменование *, вызов метода позаботится об этом автоматически.

Немного сложно ответить на ваш главный вопрос, так как я не знаю, что именно вы пробовали и почему это не сработало.

Довольно прямой перевод того, что вы написали, в синтаксис итератора работает:

map.values()
    .map(|v| v.iter().cloned().cloned().collect::<Vec<String>>())
    .collect()

Однако я бы посоветовал сделать что-то более похожее на ваш второй блок кода и избегать клонирования строк:

    map.values().cloned().collect::<Vec<Vec<String>>>()

Я бы сделал это:

 map.into_iter()
    .map(|(_key, values)| values)
    .collect()

Используя итератор, мы избегаем клонирования векторов.

В качестве альтернативы возьмите строки как входные по ссылке и верните их по ссылке:

pub fn group_anagrams(strs: &[String]) -> Vec<Vec<&String>> {
    let mut map: HashMap<String, Vec<&String>> = HashMap::new();
    for s in strs {
        let mut key = s.clone();
        unsafe {
            key.as_bytes_mut().sort();
        }
        (*map.entry(key).or_insert(vec![])).push(s);
    }

    map.into_iter()
        .map(|(_key, values)| values)
        .collect()
}

  • Большое спасибо!

    — доисторический пингвин


Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *