Split vector by a field, preserving order

Viewed 101

In Rust is there a simple way to split a vector like this:

let original_vec = vec![
    (14, "Foo", 62.3),
    (17, "Foo", 77.8),
    (25, "Bar", 33.7),
    (27, "Bar", 99.2),
    (61, "Foo", 17.4),
    (64, "Bar", 55.5),
    (77, "Bar", 31.2),
];

into this:

let res = vec![
    vec![
        (14, "Foo", 62.3),
        (17, "Foo", 77.8),
    ],
    vec![
        (25, "Bar", 33.7),
        (27, "Bar", 99.2),
    ],
    vec![
        (61, "Foo", 17.4),  // "Foo" again
    ],
    vec![
        (61, "Bar", 55.5),  // A separate group of "Bars"
        (77, "Bar", 31.2),
    ],
]

Just to clarify: I want to split my input vector by one of the fields in its elements. Only contiguous elements with the same field value must be put in a sub-vector. The "flattened" result vector must have the same order as the original vector.

2 Answers

I found exactly what I was looking for:

original_vec.group_by(|a, b| a.1 == b.1)

However, the group_by method is only available in Nightly at the moment of writing this and requires adding:

#![feature(slice_group_by)]

As an alternative, as Sebastian suggested, group_by() from the itertools crate could be used.

Basically I imagine the following solution

let original_vec = vec![
    (14, "Foo", 62.3),
    (17, "Foo", 77.8),
    (25, "Bar", 33.7),
    (27, "Bar", 99.2),
    (61, "Foo", 17.4),
    (64, "Bar", 55.5),
    (77, "Bar", 31.2),
];


type DATA = (i32, &'static str, f32);

let mut t: Vec<Vec<DATA>> = Vec::new();
let mut q: Vec<DATA> = Vec::new();
let mut p: DATA = (0, "", 0.0);

for i in original_vec
{
    if i.1 != p.1 && p.1 != "" {
        t.push(q);
        q = Vec::new();    
        q.push(i);
    }
    
    q.push(i);
    p = i;
}

println!("{:?}", t);
Related