rust 如何按索引排序(重新排序)Vec?

8yparm6h  于 2023-03-18  发布在  其他
关注(0)|答案(3)|浏览(217)

我想在Rust中按预定义的顺序就地排序(重新排序)一个Vec
例如:

let i = vec![0, 3, 2, 1];
let mut v = vec!["a", "b", "c", "d"];
v.sort_by_indices(&i);

assert_eq!(v, &["a", "d", "c", "b"]);

我想就地执行此操作,在我的用例中,v占用大量内存。
此问题是How to get the indices that would sort a Vec?的后续问题

oxiaedzo

oxiaedzo1#

一个就地实现是棘手的,但可能在O(n)时间内。它的工作原理是追逐索引和交换元素,直到它回到它开始的地方。不幸的是,这确实需要暂存空间来跟踪哪些元素已经排序。下面是一个实现,如果允许使用索引数组,它可以重用索引数组:

fn sort_by_indices<T>(data: &mut [T], mut indices: Vec<usize>) {
    for idx in 0..data.len() {
        if indices[idx] != idx {
            let mut current_idx = idx;
            loop {
                let target_idx = indices[current_idx];
                indices[current_idx] = current_idx;
                if indices[target_idx] == target_idx {
                    break;
                }
                data.swap(current_idx, target_idx);
                current_idx = target_idx;
            }
        }
    }
}

看看它在playground上的工作(@Jmb进行了改进)。
否则,您将需要单独分配临时空间(可能是BitVec)。如果可以在不跟踪排序元素的情况下使用此方法,请随意进行注解或编辑。

kxeu7u2r

kxeu7u2r2#

以同样的方式,它足以实现自己

let i = vec![0, 3, 2, 1];
let mut v = vec!["a", "b", "c", "d"];

v = i.into_iter().map(|x| v[x]).collect::<Vec<&str>>();

assert_eq!(v, &["a", "d", "c", "b"]);
uklbhaso

uklbhaso3#

您可以创建HashMapBTreeMap***查找表***并将其用作密钥搜索器:

use std::collections::HashMap;
fn main() {
    let i = vec![0, 3, 2, 1];
    let mut v = vec!["a", "b", "c", "d"];

    let keys: HashMap<_, _> = v.iter().cloned().zip(i.iter()).collect();
    v.sort_by_cached_key(|e| keys[e]);

    assert_eq!(v, &["a", "d", "c", "b"]);
}

Playground

相关问题