# Get multiple &mut from a vector, or any iterator

**URL:** <https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771>\
**Category:** Uncategorized\
**Created:** [November 18, 2022, 6:58pm UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771 "2022-11-18T18:58:46Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![0xforerunner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/0xforerunner/32/13884_2.png) [@0xforerunner](https://internals.rust-lang.org/u/0xforerunner)\
**Post date:** [November 18, 2022, 6:58pm UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/1 "2022-11-18T18:58:46Z")

</div>

function for Iterator should look like this

```rust
pub fn get_muts<K, F, const LEN: usize>(&mut self, f: F) -> Result<[&mut T; LEN]>
where
    Self: Sized,
    F: FnMut(Self::Item, [&mut K; LEN]) -> bool,

```

Is this posible? I think it would be hugely useful.

---

<div class="post-metadata">

**Author:** ![T4r4sB](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/t4r4sb/32/10037_2.png) [@T4r4sB](https://internals.rust-lang.org/u/T4r4sB)\
**Post date:** [November 18, 2022, 7:07pm UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/2 "2022-11-18T19:07:46Z")

</div>

Could you write possible implementation on pseudo-code (without corresponding Rust's borrrow-checker rules), please?

---

<div class="post-metadata">

**Author:** ![0xforerunner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/0xforerunner/32/13884_2.png) [@0xforerunner](https://internals.rust-lang.org/u/0xforerunner)\
**Post date:** [November 18, 2022, 7:45pm UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/3 "2022-11-18T19:45:53Z")

</div>

Here is a horrible prototype of this function. Should get the general point across

```rust
pub fn get_muts<'a, T, K, F, I, const LEN: usize>(collection: I, keys: [&K; LEN], mut f: F) -> [&'a mut T; LEN]
where
    T: Debug,
    I: Sized + IntoIterator<Item = &'a mut T>,
    F: FnMut(&I::Item, &K) -> bool,
{
    let mut output = Vec::with_capacity(LEN);
    unsafe { output.set_len(LEN) }
    for item in collection.into_iter() {
        for (i, key) in keys.into_iter().enumerate() {
            if f(&item, key) {
                output[i] = item;
            }
        }
    }
    output.try_into().unwrap()
}

```

There are a number of things that areproblematic here, But I hope this serves as a starting point for someone who is more comfortable with unsafe rust than I am.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [November 18, 2022, 8:10pm UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/4 "2022-11-18T20:10:57Z")

</div>

The unstable [`HashMap::get_many_mut`](https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.get_many_mut) is a similar idea.

---

<div class="post-metadata">

**Author:** ![0xforerunner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/0xforerunner/32/13884_2.png) [@0xforerunner](https://internals.rust-lang.org/u/0xforerunner)\
**Post date:** [November 18, 2022, 8:38pm UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/5 "2022-11-18T20:38:07Z")

</div>

I didn't even know that existed, but yes the idea is exactly the same, this is just for iterators instead of hash maps.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [November 18, 2022, 9:10pm UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/6 "2022-11-18T21:10:15Z")

</div>

There's a few options for slices, you can use a combination of `split_at_mut`/`split_first_mut`/`split_last_mut` or slice patterns [(playground)](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3d8ca6f951a72adc01993aa56bc80f38)

```rust
fn main() {
    let mut v = vec![1, 2, 3, 4, 5];

    let Some((a, rest)) = v.split_first_mut() else { unreachable!() };
    let [_, b, c, ..] = rest else { unreachable!() };
    *a = 7;
    *b = 8;
    *c = 9;
    dbg!(v);
}

```

(it would be nice if there were ways to avoid the fallibility of the pattern here, e.g. with `v[2..4]` that could return an `&mut [i32; 2]` rather than an `&mut [i32]` so that the fallibility is all handled within the panicking indexing operation, but I don't know that current const-generics are powerful enough to implement something like that).

For iterators that give out mutable references like `vec::IterMut` you can simply collect the references [(playground)](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=16def7cbfa7dd6ba993580931ccb6c60):

```rust
fn main() {
    let mut v = vec![1, 2, 3, 4, 5];

    let mut refs = v.iter_mut().collect::<Vec<&mut i32>>();
    *refs[1] = 7;
    *refs[2] = 8;
    dbg!(v);
}

```

For by-value iterators, you can similarly just collect part of the iterator then operate on it, there's not really anything more efficient the iterator itself can do.

---

<div class="post-metadata">

**Author:** ![0xforerunner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/0xforerunner/32/13884_2.png) [@0xforerunner](https://internals.rust-lang.org/u/0xforerunner)\
**Post date:** [November 18, 2022, 10:05pm UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/7 "2022-11-18T22:05:41Z")

</div>

Along a similar line I've implemented a very useful function for Vec which allows for getting multiple indices. It could probably be improved with some unsafe code:

```rust
#[inline]
fn get_many_mut<'a, T, I, const LEN: usize>(vec: &'a mut Vec<T>, indexes: [usize; LEN]) -> Option<[&'a mut T; LEN]>
where
    T: Debug,
    &'a mut T: Copy,
    I: Sized + IntoIterator<Item = &'a mut T>,
{
    // Create uninitialized array
    let mut data: [Option<&mut T>; LEN] = [None; LEN];

    // Fill the data
    for (vec_index, item) in vec.iter_mut().enumerate() {
        for (i, index) in indexes.into_iter().enumerate() {
            if index == vec_index {
                data[i] = Some(item);
                break;
            }
        }
    }

    // Assert initialized
    let output = data.into_iter().collect::<Option<Vec<&mut T>>>();
    output.map(|vec| vec.try_into().unwrap())
}

```

---

<div class="post-metadata">

**Author:** ![0xforerunner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/0xforerunner/32/13884_2.png) [@0xforerunner](https://internals.rust-lang.org/u/0xforerunner)\
**Post date:** [November 19, 2022, 12:02am UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/8 "2022-11-19T00:02:36Z")

</div>

So I'm starting to hone in on this. My latest iteration looks like this and is actually pretty clean I think.

```rust
pub fn find_many<'a, I, T, F, K, const LEN: usize>(collection: I, keys: [&K; LEN], mut f: F) -> Option<[&'a mut T; LEN]>
where
    I: Sized + IntoIterator<Item = &'a mut T>,
    T: Debug,
    F: FnMut(&I::Item, &K) -> bool,
{
    let mut refs = collection.into_iter();
    keys.iter()
        .map(|key| refs.find(|elem| f(elem, key)))
        .collect::<Option<Vec<&mut T>>>()
        .map(|x| x.try_into().unwrap())
}

```

I still think there are some improvements to be done with unsafe, but this is looking pretty good I think.

---

<div class="post-metadata">

**Author:** ![0xforerunner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/0xforerunner/32/13884_2.png) [@0xforerunner](https://internals.rust-lang.org/u/0xforerunner)\
**Post date:** [November 19, 2022, 12:18am UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/9 "2022-11-19T00:18:43Z")

</div>

Here's some tests to see it in action.

```rust
#[test]
fn test_find_many() {
    let mut v = vec![(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)];
    let keys = [&2, &3];
    let res = find_many(&mut v, keys, |item, key| &item.1 == key);
    let unwrapped = res.unwrap();
    assert_eq!(*unwrapped[0], (0, 2));
    assert_eq!(*unwrapped[1], (0, 3));
}

#[test]
fn test_duplicate_key() {
    let mut v = vec![(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)];
    let keys = [&2, &2];
    let res = find_many(&mut v, keys, |item, key| &item.1 == key);
    assert!(res.is_none());
}

#[test]
fn test_missing_key() {
    let mut v = vec![(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)];
    let keys = [&2, &7];
    let res = find_many(&mut v, keys, |item, key| &item.1 == key);
    assert!(res.is_none());
}

```

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [November 19, 2022, 12:39am UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/10 "2022-11-19T00:39:08Z")

</div>

Note that your implementation will only find everything if `collection` and `keys` have them in the same order. For example, keys `[&3, &2]` will advance the `refs` iterator to the first 3, but then it won't find 2 because you already passed it. Iterators won't let you revisit prior items, especially because that would allow aliasing with `&mut T` items.

---

<div class="post-metadata">

**Author:** ![0xforerunner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/0xforerunner/32/13884_2.png) [@0xforerunner](https://internals.rust-lang.org/u/0xforerunner)\
**Post date:** [November 19, 2022, 1:11am UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/11 "2022-11-19T01:11:00Z")

</div>

Damn... yup you're right. Any idea how to fix it?

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [November 19, 2022, 1:34am UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/12 "2022-11-19T01:34:30Z")

</div>

Okay, you nerd-sniped me. I used a couple nightly features, but no `unsafe`:

```rust
#![feature(array_try_map, inline_const)]

pub fn find_many<'a, I, T, F, K, const LEN: usize>(
    collection: I,
    keys: [&K; LEN],
    mut f: F,
) -> Option<[&'a mut T; LEN]>
where
    I: IntoIterator<Item = &'a mut T>,
    F: FnMut(&T, &K) -> bool,
{
    let mut remaining = LEN;
    let mut output = [const { None::<&'a mut T> }; LEN];

    if LEN > 0 {
        'collection: for elem in collection {
            for (key, out) in std::iter::zip(&keys, &mut output) {
                if out.is_none() && f(elem, key) {
                    *out = Some(elem);
                    remaining -= 1;
                    if remaining == 0 {
                        break 'collection;
                    }
                    break;
                }
            }
        }
    }

    // map [Option<&mut T>; LEN] to Option<[&mut T; LEN]>
    output.try_map(|opt| opt)
}

```

---

<div class="post-metadata">

**Author:** ![0xforerunner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/0xforerunner/32/13884_2.png) [@0xforerunner](https://internals.rust-lang.org/u/0xforerunner)\
**Post date:** [November 19, 2022, 1:50am UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/13 "2022-11-19T01:50:40Z")

</div>

Yeah that's a fantastic approach. I didn't know about either of those features. Those are super useful for this.Great job!

---

<div class="post-metadata">

**Author:** ![dlight](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dlight/32/8462_2.png) [@dlight](https://internals.rust-lang.org/u/dlight)\
**Post date:** [November 19, 2022, 5:01am UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/14 "2022-11-19T05:01:39Z")

</div>

This is very useful, what does it takes to add this to the stdlib as a method of `Vec`? Could you just send a PR?

---

<div class="post-metadata">

**Author:** ![0xforerunner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/0xforerunner/32/13884_2.png) [@0xforerunner](https://internals.rust-lang.org/u/0xforerunner)\
**Post date:** [November 19, 2022, 5:30am UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/15 "2022-11-19T05:30:38Z")

</div>

I'm thinking a PR to Itertools could potentially go through.

---

<div class="post-metadata">

**Author:** ![0xforerunner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/0xforerunner/32/13884_2.png) [@0xforerunner](https://internals.rust-lang.org/u/0xforerunner)\
**Post date:** [November 19, 2022, 5:32am UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/16 "2022-11-19T05:32:39Z")

</div>

Building on top. Another useful function to map the &mut could look like this:

````rust
/// finds multiple items in a collection and maps the elements to &muts.
///
/// ```
/// # use contracts_common::map::find_map_many;
/// # fn test_find_many() {
/// let mut v = vec![(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)];
/// let [left, right] =
/// find_map_many(&mut v, [&2, &3], |item, key| &item.0 == key, |item| &mut item.1).unwrap();
/// assert_eq!(*left, 3);
/// assert_eq!(*right, 4);
/// # }
/// ```
pub fn find_map_many<'a, I, T, U, F, M, K, const LEN: usize>(
    collection: I, keys: [&K; LEN], mut find: F, mut map: M,
) -> Option<[&'a mut U; LEN]>
where
    I: IntoIterator<Item = &'a mut T>,
    T: Debug + 'a,
    U: Debug,
    F: FnMut(&T, &K) -> bool,
    M: FnMut(&'a mut T) -> &'a mut U,
{
    let mut remaining = LEN;
    // When inline_const is stabilized this unsafe block can be removed
    let mut output: [Option<&'a mut U>; LEN] = unsafe { std::mem::zeroed() };

    'collection: for elem in collection {
        for (key, out) in std::iter::zip(&keys, &mut output) {
            if out.is_none() && find(elem, key) {
                *out = Some(map(elem));
                remaining -= 1;
                if remaining == 0 {
                    break 'collection;
                }
                break;
            }
        }
    }

    // When array_try_map is stabilized this can be made better.
    let vec = output.into_iter().collect::<Option<Vec<&mut U>>>();
    vec.map(|x| x.try_into().unwrap())
}

````

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [November 19, 2022, 9:03am UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/17 "2022-11-19T09:03:50Z")

</div>

That `std::mem::zeroed` should be fine, but you can avoid it either by using `std::array::from_fn`:

```rust
let mut output: [Option<&'a mut U>; LEN] = std::array::from_fn(|_| None);

```

Or using a `const` (needs some magic to make it generic though):

```rust
struct Helper<T>(std::marker::PhantomData<T>);
impl<T> Helper<T> {
    const NONE: Option<T> = None;
}
let mut output: [Option<&'a mut U>; LEN] = [Helper::NONE; LEN];

```

You can also avoid `collect`ing into a `Vec` if you first check the `Option`s and then `unwrap` them inside an `array::map`:

```rust
let () = output.iter().map(|r| r.as_ref().map(|_| ())).collect::<Option<()>>()?;
Some(output.map(Option::unwrap))

```

---

<div class="post-metadata">

**Author:** ![2e71828](https://avatars.discourse-cdn.com/v4/letter/2/3e96dc/32.png) [@2e71828](https://internals.rust-lang.org/u/2e71828)\
**Post date:** [November 19, 2022, 12:47pm UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/18 "2022-11-19T12:47:01Z")

</div>

Does it make sense to define an `unsafe trait DisjointIterator: Iterator` that promises to never yield the same value twice? Then these sort of multiple-mutable-fetch operations can use that as a bound instead of relying on their own internal checks.

Integer ranges, set iterators, and dictionary key iterators could all implement it, as could filters of these.

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [November 19, 2022, 3:46pm UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/19 "2022-11-19T15:46:58Z")

</div>

> [@2e71828](#):
>
> Does it make sense to define an `unsafe trait DisjointIterator: Iterator` that promises to never yield the same value twice?

For that you also need a notion of equality that you can trust. User types can implement `Eq` in such a way that they appear different when being yielded from the iterator but equal afterwards. This is particularly important if you want to implement it for sets and dictionary keys iterators.

But even then, I'm not sure if this is really an improvement. It would forse users to statically prove that their keys are disjoint (What if you want to use `[&1, &3, &4]` for the keys?) and also wouldn't really improve the implementation (the `break` at the end of the `if` is required by the borrow checker, but is also an optimization which you likely want to keep).

---

<div class="post-metadata">

**Author:** ![2e71828](https://avatars.discourse-cdn.com/v4/letter/2/3e96dc/32.png) [@2e71828](https://internals.rust-lang.org/u/2e71828)\
**Post date:** [November 19, 2022, 4:39pm UTC](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771/20 "2022-11-19T16:39:45Z")

</div>

> [@SkiFire13](#):
>
> It would forse users to statically prove that their keys are disjoint (What if you want to use `[&1, &3, &4]` for the keys?) and also wouldn't really improve the implementation (the `break` at the end of the `if` is required by the borrow checker, but is also an optimization which you likely want to keep).

It would force the disjointness check outside of the actual multiple-borrowing code, but it doesn't necessarily need to be statically proven: There would likely need to be a helper for dynamic checking, which could be omitted in those cases that are statically provable. For the case of slices like `[&1, &3, &4]`, that helper could be implemented as a `const fn` so that the checking happens in the constant-folding optimization pass. I agree that it wouldn't improve matters much for _this specific function_ because the `Iterator` interface forces considering each candidate in sequence— It would be more useful for inherent methods on the original collection types.

> [@SkiFire13](#):
>
> For that you also need a notion of equality that you can trust. User types can implement `Eq` in such a way that they appear different when being yielded from the iterator but equal afterwards.

That may kill this idea as a practical matter. `std` couldn't have blanket `TrustedIterator` implementations, only ones for concrete types known to implement `Eq` sanely. The only way to get the blanket implementation back would be to add some kind of `unsafe trait TrustedEq {}`, which feels like the start of a potentially-very-deep rabbit hole.

[Next page](https://internals.rust-lang.org/t/get-multiple-mut-from-a-vector-or-any-iterator/17771.md?page=2)
