How can min_by_key be used with peekable iterators?


Hello everyone,

I am new to rust and currently trying to merge bunches of sorted iterators (each iterator is reading from a huge file)

My first attempt is to use min_by_key like this:

        // v is a vector of `BufReader.lines().peekable()`
        let mut iter = v.iter().min_by_key(|x| {
            match x.peek() { 
                Some(line) => {
                    match line {
                        Ok(line) => line.len() as u64,
                        _ => std::u64::MAX,
                None => std::u64::MAX,
       // do something with ``

However, the compiler returns with an error telling:

> match x.peek()
cannot borrow `**x` as mutable, as it is behind a `&` reference

So I am having two questions:

  1. why peek wants to borrow x as mutable? As far as I am concerned, peek is not consuming the iterator.
  2. What should I do to avoid the error?

Thanks in advance.


peek needs mutable access to the iterator, because it needs to prefetch the next element and store it, and that changes the state of the iterator.

Unfortunately min_by_key by design only lets you see the item, not modify it.

Your best bet would be to write your own for loop with a mutable iterator, and pick the min element manually.

If you really had to use min_by_key, then you’d have to wrap the peekable iterators in RefCell/Mutex that can mutate an object behind a shared reference.

1 Like

For those who interested, I end up something like this:

        let (idx, _) = vec.iter_mut()
                          .fold((None, std::u64::MAX), |(ia, a), (ib, b)| {
            let val = match b.peek() {
                Some(line) => line.len() as u64,
                None => std::u64::MAX,
            if val < a { (Some(ib), val) } else { (ia, a) }
1 Like