9

I understand how to operate on an entire vector, though I don't think this is idiomatic Rust:

fn median(v: &Vec<u32>) -> f32 {
    let count = v.len();
    if count % 2 == 1 {
        v[count / 2] as f32
    } else {
        (v[count / 2] as f32 + v[count / 2 - 1] as f32) / 2.0
    }
}

fn main() {
    let mut v1 = vec![3, 7, 8, 5, 12, 14, 21, 13, 18];
    v1.sort();
    println!("{:.*}", 1, median(&v1));
}

But what if I want to operate on only half of this vector? For example, the first quartile is the median of the lower half, and the third quartile is the median of the upper half. My first thought was to construct two new vectors, but that did not seem quite right.

How do I get "half" a vector?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Rob Latham
  • 5,085
  • 3
  • 27
  • 44
  • 1
    Regarding how to pass iterators please check [here](http://stackoverflow.com/questions/34969902/how-to-write-a-rust-function-that-takes-an-iterator). For your first question you can take a slice, eg `let slice = &v1[0..v1.len()/2]` – Jack Nov 05 '16 at 03:25
  • [One question per question, please](http://meta.stackexchange.com/q/39223/281829). Since your "accept an iterator" question already has a duplicate, I've just removed it. – Shepmaster Nov 05 '16 at 14:16

2 Answers2

14

As mentioned, you want to create a slice using the Index trait with a Range:

let slice = &v1[0..v1.len() / 2];

This is yet another reason why it is discouraged to accept a &Vec. The current code would require converting the slice into an allocated Vec. Instead, rewrite it to accept a slice:

fn median(v: &[u32]) -> f32 {
    // ...
}

Since you are likely interested in splitting a vector / slice in half and getting both parts, split_at may be relevant:

let (head, tail) = v1.split_at(v1.len() / 2);
println!("{:.*}", 1, median(head));
println!("{:.*}", 1, median(tail));
Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
1

How to find the median on vector:

fn median(numbers: &mut Vec<i32>) -> i32 {
    numbers.sort();
    let mid = numbers.len() / 2;

    if numbers.len() % 2 == 0 {
        mean(&vec![numbers[mid - 1], numbers[mid]]) as i32
    } else {
        numbers[mid]
    }

}

How to get half a vector:

  • Use Slice:
let slice: &[i32] = &numbers[0..numbers.len() / 2];
  • Creates a draining iterator
let half: Vec<i32> = numbers.drain(..numbers.len()/2).collect()
Little Roys
  • 5,383
  • 3
  • 30
  • 28
  • I like this answer, so I am wondering why it gets no love. I'll assume the first code block works, it answers the implied question about idiomaticness. The second "Slice" code is the same as part of the accepted answer, but it is missing the discouragement. The third taught me a bunch. The drain iterator removes the portion that it iterates over, in this case the original vector "numbers" will contain only the last half. So this is similar to the split_at(). – David Lotts Jan 14 '22 at 05:14
  • After all my noob analysis and study of the std::Vec documentation, I have decided that there are at least half a dozen ways of getting half a vector, including drain, split_at, split_off, resize, resize_default, and truncate. – David Lotts Jan 14 '22 at 05:14