How to partition vector of results in Rust? - rust

Basically, I'm looking for the partitionEithers equivalent in Rust, i.e. to convert Vec<Result<A, B>> into Result<Vec<A>, Vec<B>>.
I know I can transform a Vec<Result<A, B>> into Result<Vec<A>, B> by using collect::<Result<Vec<A>, B>>, but when I try collect::<Result<Vec<A>, Vec<B>>>, I'll get an error saying such implementation is missing.
Also I know this can be done using mutations, but I'm wondering if there are any immutable alternatives that I can look into?

You can partition by using the partition() method, on your particular case, use partition_map() from itertools:
use itertools::{Either, Itertools};
fn main() {
let successes_and_failures = vec![Ok(1), Err(false), Err(true), Ok(2)];
let (successes, failures): (Vec<_>, Vec<_>) =
successes_and_failures
.into_iter()
.partition_map(|r| match r {
Ok(v) => Either::Left(v),
Err(v) => Either::Right(v),
});
assert_eq!(successes, [1, 2]);
assert_eq!(failures, [false, true]);
}

Related

Is there a nicer way to create a vector from indexed data in rust?

I have the problem, that I get some data from an iterator (specifically a bevy Query) and part of that data is an index. I now want to create a vector with this data, where every element is placed at the index it is intended to go.
To illustrate the problem, this is how I might solve this in python:
def iterator():
# The iterator doesn't necessarily give back the data in the correct order
# However, the indices are always dense from 0...n
yield ("A", 0)
yield ("C", 2)
yield ("B", 1)
def some_computation(x):
return x + " + some other data"
data_list = [0] * 3 # I know the length
for data, index in iterator():
data_list[index] = some_computation(data)
print(data_list)
Below is how I currently implemented this in rust, but I'm not super happy about it. Firstly, it takes O(n log n) time.
Secondly, its feels difficult to read, especially the conversion to get rid of the index in the data.
Thirdly, I haven't yet figured out how to extract this into its own function without violating lifetimes.
Open in the Rust Playground
// I have so far avoided deriving Clone on this struct.
#[derive(Debug)]
struct OwnedDataWithReference<'a> {
data: &'a str,
}
fn do_something_with_data_list_and_drop_it(x: Vec<OwnedDataWithReference>) {
println!("{:?}", x);
}
fn main() {
// In my application this is a bevy query, which can't be indexed.
let iterator = vec![("A", 0), ("C", 2), ("B", 1)];
// First the data is created and stored in a vector with a index associated
// and only subsequently sorted, which costs runtime, but has nice ownership.
let mut data_list_with_index = Vec::new();
for (data_ref, index) in iterator.iter() {
// In my application I first have to fetch data using data_ref
let new_data = OwnedDataWithReference {
data: data_ref,
};
data_list_with_index.push((new_data, index));
}
// This reverse sort and stack based map is needed because I don't want to
// make `OwnedDataWithReference` Clone. This way, I can transfer ownership.
data_list_with_index.sort_by_key(|(_, i)| -*i);
let mut data_list = Vec::new();
while !data_list_with_index.is_empty() {
data_list.push(data_list_with_index.pop().unwrap().0);
}
// In my application I then serialize this with serde.
do_something_with_data_list_and_drop_it(data_list);
}
I have tried an approach with using Vec<Option<OwnedDataWithReference>>, but this complained that OwnedDataWithReference is not Clone, which I've tried to avoid so far.
Please let me know if you can find a nicer solution to this problem, or if you think I should derive Clone. (The problem is still not solved then, but I think it gets easier)
I have tried an approach with using Vec<Option<OwnedDataWithReference>>, but this complained that OwnedDataWithReference is not Clone, which I've tried to avoid so far.
You probably tried creating a Vec of None values using the vec! macro which requires T: Clone. You can instead create it using another way, for example (0..n).map(|_| None).collect(). With that, this can be done like this:
#[derive(Debug)]
struct OwnedDataWithReference<'a> {
data: &'a str,
other_stuff: u32,
}
fn do_something_with_data_list_and_drop_it(x: Vec<OwnedDataWithReference>) {
println!("{:?}", x);
}
fn main() {
let iterator = vec![("A", 0), ("C", 2), ("B", 1)];
let mut data_list = (0..iterator.len()).map(|_| None).collect::<Vec<_>>();
for (data_ref, index) in iterator.iter() {
let new_data = OwnedDataWithReference {
data: data_ref,
other_stuff: 42,
};
data_list[*index] = Some(new_data);
}
// This will panic if any element is still `None` at this point.
let data_list = data_list.into_iter().map(Option::unwrap).collect();
do_something_with_data_list_and_drop_it(data_list);
}
Playground

Rust stacked optional in while let

I am really new in rust, and while going through the rustlings exercises I found something I do not fully understand regarding stacked Options.
Given the following code:
let vector = vec![Some(24), None, Some(42)];
let mut iter = vector.iter();
while let Some(Some(number)) = iter.next() {
println!("Number: {}", number);
}
I would expect to see the following output:
Number: 24
Number: 42
But I guess as soon as rust encounters the None, the while loop exits, only printing the 24
What would be the most idiomatic rust code to iterate and unwrap optional values?
The closest that I got would look something like this:
let mut iter = vector.iter();
while let Some(iterNext) = iter.next() {
if let Some(num) = iterNext {
println!("Number: {}", num);
}
}
Or it could also be done by checking the existence in a for loop:
for opt in &vector {
if opt.is_some() {
println!("Number: {}", opt.unwrap());
}
}
Another nice way to write this code is
for num in vector.iter().flatten() {
println!("{}", num);
}
The flatten() method on an iterator treats each item of the iterator as an iterator, and returns an iterator over all these iterators chained together. Option is an iterator that yields one element if it is Some, or none for None, so flatten() is exactly what we want here.
Of course you could also write this using for_each(), but for code with side effects I generally prefer for loops.
I would expect to see the following output: [...]
A while loop that encounters a false condition exits - but that's not specific to Rust, it's just how while loops work.
An idiomatic solution would probably combine your last two snippets:
for opt in &vector {
if let Some(num) = opt {
println!("Number: {}", num);
}
}
Just a simple for loop containing an if let, no unwrapping required.
Another idiomatic variant is to use iterator adapters:
vector
.iter()
.filter_map(|opt| opt.as_ref())
.for_each(|num| println!("{}", num));
Note that here we could use filter(Option::is_some), but then we would be left with options and would have to use unwrap() to get to the values. This is where
filter_map() comes in useful: it filters the Some values (after applying the map function), and at the same time extracts the values inside. opt.as_ref() serves to trivially convert &Option<T>, obtained from iterating a vector of options by reference, to Option<&T> which filter_map expects returned.
Using and_then to filter out the None's and only delivering Some's to the programs working part:
let vector = vec![Some(24), None, Some(42)];
for num in vector.iter() {
num.and_then::<i32, fn(i32) -> Option<i32>>(|n| {
println!("{}", n); // …working part
None
});
}

How to initialize an array of Vec? [duplicate]

I’m trying to initialize a fixed-size array of some nullable, non-copyable type, like an Option<Box<Thing>> for some kind of Thing. I’d like to pack two of them into a struct without any extra indirection. I’d like to write something like this:
let array: [Option<Box<Thing>>; SIZE] = [None; SIZE];
But it doesn’t work because the [e; n] syntax requires that e implements Copy. Of course, I could expand it into SIZE Nones, but that can be unwieldy when SIZE is large. I don’t believe this can be done with a macro without an unnatural encoding of SIZE. Is there a good way to do it?
Yes, this is easy with unsafe; is there a way to do it without unsafe?
As of Rust 1.38 (released in September 2019), a cleaner alternative to previously posted answers is possible using an intermediate const initializer. This approach works for arrays of any size:
const SIZE: usize = 100;
const INIT: Option<Box<Thing>> = None;
let array: [Option<Box<Thing>>; SIZE] = [INIT; SIZE];
(It works with or without the Box; the example uses Box because it was used in the question.)
One limitation is that the array item must have a default representation that can be evaluated at compile time - a constant, enum variant, or a primitive container composed of those. None or a tuple of numbers will work, but a non-empty Vec or String won't.
You could use the Default trait to initialize the array with default values:
let array: [Option<Box<Thing>>; SIZE] = Default::default();
See this playground for a working example.
Note that this will only work for arrays with up to 32 elements, because Default::default is only implemented for up to [T; 32]. See https://doc.rust-lang.org/std/default/trait.Default.html#impl-Default-for-%5BT%3B%2032%5D.
As of Rust 1.55.0 (which introduced [T]::map()), the following will work:
const SIZE: usize = 100;
#[derive(Debug)]
struct THING { data: i64 }
let array = [(); SIZE].map(|_| Option::<THING>::default());
for x in array {
println!("x: {:?}", x);
}
Rust Playground
I'm copying the answer by chris-morgan and adapting it to match the question better, to follow the recommendation by dbaupp downthread, and to match recent syntax changes:
use std::mem;
use std::ptr;
#[derive(Debug)]
struct Thing {
number: usize,
}
macro_rules! make_array {
($n:expr, $constructor:expr) => {{
let mut items: [_; $n] = mem::uninitialized();
for (i, place) in items.iter_mut().enumerate() {
ptr::write(place, $constructor(i));
}
items
}}
}
const SIZE: usize = 50;
fn main() {
let items = unsafe { make_array!(SIZE, |i| Box::new(Some(Thing { number: i }))) };
println!("{:?}", &items[..]);
}
Note the need to use unsafe here: The problem is that if the constructor function panic!s, this would lead to undefined behavior.
Go through the heap
If you can create a Vec of your type, you can convert it into an array:
use std::convert::TryInto;
#[derive(Clone)]
struct Thing;
const SIZE: usize = 100;
fn main() {
let v: Vec<Option<Thing>> = vec![None; SIZE];
let v: Box<[Option<Thing>; SIZE]> = match v.into_boxed_slice().try_into() {
Ok(v) => v,
Err(_) => unreachable!(),
};
let v: [Option<Thing>; SIZE] = *v;
}
In many cases, you actually want to leave it as a Vec<T>, Box<[T]>, or Box<[T; N]> as these types all put the data in the heap. Large arrays tend to be... large... and you don't want all that data on the stack.
See also:
What is the use of into_boxed_slice() methods?
How to get a slice as an array in Rust?
How do I get an owned value out of a `Box`?
Keep it simple
Type out all the values:
struct Thing;
const SIZE: usize = 5;
fn main() {
let array: [Option<Box<Thing>>; SIZE] = [None, None, None, None, None];
}
You could use a build script to generate this code for you. For an example of this, see:
How to create a static string at compile time
An alternative approach using the arrayvec crate that generalizes easily to situations other than initializing everything with a fixed value:
use arrayvec::ArrayVec;
let array = std::iter::repeat(None)
.take(SIZE)
.collect::<ArrayVec<Option<Box<Thing>>, SIZE>>()
.into_inner()
.unwrap();
(playground)
On nightly Rust, you can use inline const. This is a variant of the answer by #user4815162342, but one that doesn't require you to declare a separate constant and repeat the type:
#![feature(inline_const)]
let array: [Option<Box<Thing>>; SIZE] = [const { None }; SIZE];
Until this is stabilized (hopefully soon), you can also use the inline-const crate, but this does require you to repeat the type.
let stackoverflow: [Option<&mut ()>;0xDEADBEEF] = std::array::from_fn(|_| None);
dbg!(stackoverflow);
playground

How do you write an iterator to a File or Stdout (anything implementing Write)?

I have an iterator full of u8's that I want to write to a file or stdout. Calling io::stdout().write_all(foo) on my iterator gives me an expected type &[u8], and that I have an iterator type instead. I understand why this doesn't work.
What I don't understand is how to change it so that it does work. At first I tried adding a .collect() to the end of my iterator, but then it says the trait bound &[u8]: std::iter::FromIterator<u8> is not satisfied and a collection of type &[u8] cannot be built from an iterator over elements of type u8.
It seems odd to me that Write doesn't provide a way of writing with an iterator, when Read provides a bytes() function that returns an iterator. What is the idiomatic way to do this?
Here is my main function's contents:
io::stdout().write_all(
io::stdin().bytes().map(
|x| match x {
Ok(b) => b,
_ => panic!("There was an error reading from stdin"),
}
).repeat(3).collect()
);
It seems odd to me that Write doesn't provide a way of writing with an iterator, when Read provides a bytes() function that returns an iterator. What is the idiomatic way to do this?
It does feel inconsistent, indeed, but you can certainly write the equivalent yourself.
Something like:
fn write_all<W: Write, I: Iterator<Item=u8>>(writer: &mut W, iter: I) {
const SIZE: usize = 1024;
let mut buffer = [0u8; SIZE];
let mut index = 0;
for i in iter {
buffer[index] = i;
index += 1;
if index == SIZE {
writer.write_all(&buffer);
}
}
writer.write_all(&buffer[..index]);
}
There are probably ways to make it more idiomatic, and I haven't tested the boundary conditions, but hopefully it should get you going.
The problem is that you want to build a Vec<u8>, but are attempting to create a Vec<&u8>. You can do the following:
fn main() {
let array = [1u8, 2, 3];
let vector: Vec<u8> = array.iter().map(|i| *i).collect();
}
Note the .map(|i| *i) part that allows to go from &u8 references to u8 values.

Initialize a large, fixed-size array with non-Copy types

I’m trying to initialize a fixed-size array of some nullable, non-copyable type, like an Option<Box<Thing>> for some kind of Thing. I’d like to pack two of them into a struct without any extra indirection. I’d like to write something like this:
let array: [Option<Box<Thing>>; SIZE] = [None; SIZE];
But it doesn’t work because the [e; n] syntax requires that e implements Copy. Of course, I could expand it into SIZE Nones, but that can be unwieldy when SIZE is large. I don’t believe this can be done with a macro without an unnatural encoding of SIZE. Is there a good way to do it?
Yes, this is easy with unsafe; is there a way to do it without unsafe?
As of Rust 1.38 (released in September 2019), a cleaner alternative to previously posted answers is possible using an intermediate const initializer. This approach works for arrays of any size:
const SIZE: usize = 100;
const INIT: Option<Box<Thing>> = None;
let array: [Option<Box<Thing>>; SIZE] = [INIT; SIZE];
(It works with or without the Box; the example uses Box because it was used in the question.)
One limitation is that the array item must have a default representation that can be evaluated at compile time - a constant, enum variant, or a primitive container composed of those. None or a tuple of numbers will work, but a non-empty Vec or String won't.
You could use the Default trait to initialize the array with default values:
let array: [Option<Box<Thing>>; SIZE] = Default::default();
See this playground for a working example.
Note that this will only work for arrays with up to 32 elements, because Default::default is only implemented for up to [T; 32]. See https://doc.rust-lang.org/std/default/trait.Default.html#impl-Default-for-%5BT%3B%2032%5D.
As of Rust 1.55.0 (which introduced [T]::map()), the following will work:
const SIZE: usize = 100;
#[derive(Debug)]
struct THING { data: i64 }
let array = [(); SIZE].map(|_| Option::<THING>::default());
for x in array {
println!("x: {:?}", x);
}
Rust Playground
I'm copying the answer by chris-morgan and adapting it to match the question better, to follow the recommendation by dbaupp downthread, and to match recent syntax changes:
use std::mem;
use std::ptr;
#[derive(Debug)]
struct Thing {
number: usize,
}
macro_rules! make_array {
($n:expr, $constructor:expr) => {{
let mut items: [_; $n] = mem::uninitialized();
for (i, place) in items.iter_mut().enumerate() {
ptr::write(place, $constructor(i));
}
items
}}
}
const SIZE: usize = 50;
fn main() {
let items = unsafe { make_array!(SIZE, |i| Box::new(Some(Thing { number: i }))) };
println!("{:?}", &items[..]);
}
Note the need to use unsafe here: The problem is that if the constructor function panic!s, this would lead to undefined behavior.
Go through the heap
If you can create a Vec of your type, you can convert it into an array:
use std::convert::TryInto;
#[derive(Clone)]
struct Thing;
const SIZE: usize = 100;
fn main() {
let v: Vec<Option<Thing>> = vec![None; SIZE];
let v: Box<[Option<Thing>; SIZE]> = match v.into_boxed_slice().try_into() {
Ok(v) => v,
Err(_) => unreachable!(),
};
let v: [Option<Thing>; SIZE] = *v;
}
In many cases, you actually want to leave it as a Vec<T>, Box<[T]>, or Box<[T; N]> as these types all put the data in the heap. Large arrays tend to be... large... and you don't want all that data on the stack.
See also:
What is the use of into_boxed_slice() methods?
How to get a slice as an array in Rust?
How do I get an owned value out of a `Box`?
Keep it simple
Type out all the values:
struct Thing;
const SIZE: usize = 5;
fn main() {
let array: [Option<Box<Thing>>; SIZE] = [None, None, None, None, None];
}
You could use a build script to generate this code for you. For an example of this, see:
How to create a static string at compile time
An alternative approach using the arrayvec crate that generalizes easily to situations other than initializing everything with a fixed value:
use arrayvec::ArrayVec;
let array = std::iter::repeat(None)
.take(SIZE)
.collect::<ArrayVec<Option<Box<Thing>>, SIZE>>()
.into_inner()
.unwrap();
(playground)
On nightly Rust, you can use inline const. This is a variant of the answer by #user4815162342, but one that doesn't require you to declare a separate constant and repeat the type:
#![feature(inline_const)]
let array: [Option<Box<Thing>>; SIZE] = [const { None }; SIZE];
Until this is stabilized (hopefully soon), you can also use the inline-const crate, but this does require you to repeat the type.
let stackoverflow: [Option<&mut ()>;0xDEADBEEF] = std::array::from_fn(|_| None);
dbg!(stackoverflow);
playground

Resources