Concatenate array slices - rust

I have two (very large) arrays foo and bar of the same type. To be able to write some nice code, I would like to obtain a read-only slice, result, of the concatenation of the two arrays. This operation must run in O(1) time and space.
Array access for result must also be in O(1). More generally, if result were the concatenation of k array slices, an arbitrary array access for result should run in O(k).
I do not want to copy any elements of foo nor bar.
This would seem to be easy to implement into the Rust core, but no amount of searching has brought me a solution.

There isn't a predefined type, but you can easily create your own by implementing the Index trait for a type that holds both your slices:
use std::ops::Index;
struct Slice<'a, T: 'a>(&'a[T], &'a[T]);
impl<'a, T: 'a> Index<usize> for Slice<'a, T> {
type Output = T;
fn index(&self, index: usize) -> &T {
if index < self.0.len() {
&self.0[index]
} else {
&self.1[index - self.0.len()]
}
}
}
More generally, if result were the concatenation of k array slices, an arbitrary array access for result should run in O(k).
You can get slice access in O(log(k)), if your slice concatenation is O(k), by creating an array that holds the cumulative lengths of the slices and using a binary search to find the actual slice to index into.
This would require a macro, because we don't have a good enough constant evaluator yet and no value generics.

I'm afraid what you are asking is pretty much impossible if you require the result to be an actual slice. A slice is a view into a block of memory. Contiguous memory. If you want a new slice by combining two other slices you have to copy the contents to a new location, so that you get a new contiguous block of memory.
If you are satisfied just concatenating by copying SliceConcatExt provides the methods concat and join on slices, which can be used on slices of custom types as long as they implement Clone:
#[derive(Clone, PartialEq, Debug)]
struct A {
a: u64,
}
fn main() {
assert_eq!(["hello", "world"].concat(), "helloworld");
assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
assert_eq!([[A { a: 1 }, A { a: 2 }], [A { a: 3 }, A { a: 4 }]].concat(),
[A { a: 1 }, A { a: 2 }, A { a: 3 }, A { a: 4 }]);
}
Note that even though SliceConcatExt is unstable, the methods themselves are stable. So there is no reason not to use them if copying is OK. If you can't copy you can't get a slice. In that case, you need to create a wrapper type, as explained in the answer of ker.

For n arrays, you can implement it using a Vec like below:
use std::ops::Index;
struct VecSlice<'a, T: 'a>(Vec<&'a [T]>);
impl<'a, T> Index<usize> for VecSlice<'a, T> {
type Output = T;
fn index(&self, mut index: usize) -> &T {
for slice in self.0.iter() {
if index < slice.len() {
return &slice[index];
} else {
index -= slice.len();
}
}
panic!("out of bound");
}
}
And then access it like an array, just don't go out of bound.
fn main() {
let a1 = [0, 1, 2];
let a2 = [7, 8, 9];
let a = VecSlice(vec!(&a1, &a2));
println!("{}", a[4]);
}
This prints out
8

Related

How to use map function to collect an array of string? [duplicate]

I want to call .map() on an array of enums:
enum Foo {
Value(i32),
Nothing,
}
fn main() {
let bar = [1, 2, 3];
let foos = bar.iter().map(|x| Foo::Value(*x)).collect::<[Foo; 3]>();
}
but the compiler complains:
error[E0277]: the trait bound `[Foo; 3]: std::iter::FromIterator<Foo>` is not satisfied
--> src/main.rs:8:51
|
8 | let foos = bar.iter().map(|x| Foo::Value(*x)).collect::<[Foo; 3]>();
| ^^^^^^^ a collection of type `[Foo; 3]` cannot be built from an iterator over elements of type `Foo`
|
= help: the trait `std::iter::FromIterator<Foo>` is not implemented for `[Foo; 3]`
How do I do this?
The issue is actually in collect, not in map.
In order to be able to collect the results of an iteration into a container, this container should implement FromIterator.
[T; n] does not implement FromIterator because it cannot do so generally: to produce a [T; n] you need to provide n elements exactly, however when using FromIterator you make no guarantee about the number of elements that will be fed into your type.
There is also the difficulty that you would not know, without supplementary data, which index of the array you should be feeding now (and whether it's empty or full), etc... this could be addressed by using enumerate after map (essentially feeding the index), but then you would still have the issue of deciding what to do if not enough or too many elements are supplied.
Therefore, not only at the moment one cannot implement FromIterator on a fixed-size array; but even in the future it seems like a long shot.
So, now what to do? There are several possibilities:
inline the transformation at call site: [Value(1), Value(2), Value(3)], possibly with the help of a macro
collect into a different (growable) container, such as Vec<Foo>
...
Update
This can work:
let array: [T; N] = something_iterable.[into_]iter()
.collect::<Vec<T>>()
.try_into()
.unwrap()
In newer version of rust, try_into is included in prelude, so it is not necessary to use std::convert::TryInto. Further, starting from 1.48.0, array support directly convert from Vec type, signature from stdlib source:
fn try_from(mut vec: Vec<T, A>) -> Result<[T; N], Vec<T, A>> {
...
}
Original Answer
as of rustc 1.42.0, if your element impl Copy trait, for simplicity, this just works:
use std::convert::TryInto;
...
let array: [T; N] = something_iterable.[into_]iter()
.collect::<Vec<T>>()
.as_slice()
.try_into()
.unwrap()
collect as_slice try_into + unwrap()
Iterator<T> ------> Vec<T> -------> &[T] ------------------> [T]
But I would just call it a workaround.
You need to include std::convert::TryInto because the try_into method is defined in the TryInto trait.
Below is the signature checked when you call try_into as above, taken from the source. As you can see, that requires your type T implement Copy trait, so theoritically, it will copy all your elements once.
#[stable(feature = "try_from", since = "1.34.0")]
impl<T, const N: usize> TryFrom<&[T]> for [T; N]
where
T: Copy,
[T; N]: LengthAtMost32,
{
type Error = TryFromSliceError;
fn try_from(slice: &[T]) -> Result<[T; N], TryFromSliceError> {
<&Self>::try_from(slice).map(|r| *r)
}
}
While you cannot directly collect into an array for the reasons stated by the other answers, that doesn't mean that you can't collect into a data structure backed by an array, like an ArrayVec:
use arrayvec::ArrayVec; // 0.7.0
use std::array;
enum Foo {
Value(i32),
Nothing,
}
fn main() {
let bar = [1, 2, 3];
let foos: ArrayVec<_, 3> = array::IntoIter::new(bar).map(Foo::Value).collect();
let the_array = foos
.into_inner()
.unwrap_or_else(|_| panic!("Array was not completely filled"));
// use `.expect` instead if your type implements `Debug`
}
Pulling the array out of the ArrayVec returns a Result to deal with the case where there weren't enough items to fill it; the case that was discussed in the other answers.
For your specific problem, Rust 1.55.0 allows you to directly map an array:
enum Foo {
Value(i32),
Nothing,
}
fn main() {
let bar = [1, 2, 3];
let foos = bar.map(Foo::Value);
}
In this case you can use Vec<Foo>:
#[derive(Debug)]
enum Foo {
Value(i32),
Nothing,
}
fn main() {
let bar = [1, 2, 3];
let foos = bar.iter().map(|&x| Foo::Value(x)).collect::<Vec<Foo>>();
println!("{:?}", foos);
}
.collect() builds data structures that can have arbitrary length, because the iterator's item number is not limited in general. (Shepmaster's answer already provides plenty details there).
One possibility to get data into an array from a mapped chain without allocating a Vec or similar is to bring mutable references to the array into the chain. In your example, that'd look like this:
#[derive(Debug, Clone, Copy)]
enum Foo {
Value(i32),
Nothing,
}
fn main() {
let bar = [1, 2, 3];
let mut foos = [Foo::Nothing; 3];
bar.iter().map(|x| Foo::Value(*x))
.zip(foos.iter_mut()).for_each(|(b, df)| *df = b);
}
The .zip() makes the iteration run over both bar and foos in lockstep -- if foos were under-allocated, the higher bars would not be mapped at all, and if it were over-allocated, it'd keep its original initialization values. (Thus also the Clone and Copy, they are needed for the [Nothing; 3] initialization).
You can actually define a Iterator trait extension to do this!
use std::convert::AsMut;
use std::default::Default;
trait CastExt<T, U: Default + AsMut<[T]>>: Sized + Iterator<Item = T> {
fn cast(mut self) -> U {
let mut out: U = U::default();
let arr: &mut [T] = out.as_mut();
for i in 0..arr.len() {
match self.next() {
None => panic!("Array was not filled"),
Some(v) => arr[i] = v,
}
}
assert!(self.next().is_none(), "Array was overfilled");
out
}
}
impl<T, U: Iterator<Item = T>, V: Default + AsMut<[T]>> CastExt<T, V> for U { }
fn main () {
let a: [i32; 8] = (0..8).map(|i| i * 2).cast();
println!("{:?}", a); // -> [0, 2, 4, 6, 8, 10, 12, 14]
}
Here's a playground link.
This isn't possible because arrays do not implement any traits. You can only collect into types which implement the FromIterator trait (see the list at the bottom of its docs).
This is a language limitation, since it's currently impossible to be generic over the length of an array and the length is part of its type. But, even if it were possible, it's very unlikely that FromIterator would be implemented on arrays because it'd have to panic if the number of items yielded wasn't exactly the length of the array.
You may combine arrays map method with Iterator::next.
Example:
fn iter_to_array<Element, const N: usize>(mut iter: impl Iterator<Item = Element>) -> [Element; N] {
// Here I use `()` to make array zero-sized -> no real use in runtime.
// `map` creates new array, which we fill by values of iterator.
let res = [(); N].map(|_| iter.next().unwrap());
// Ensure that iterator finished
assert!(matches!(iter.next(), None));
res
}
I ran into this problem myself — here's a workaround.
You can't use FromIterator, but you can iterate over the contents of a fixed-size object, or, if things are more complicated, indices that slice anything that can be accessed. Either way, mutation is viable.
For example, the problem I had was with an array of type [[usize; 2]; 4]:
fn main() {
// Some input that could come from another function and thus not be mutable
let pairs: [[usize; 2]; 4] = [[0, 0], [0, 1], [1, 1], [1, 0]];
// Copy mutable
let mut foo_pairs = pairs.clone();
for pair in foo_pairs.iter_mut() {
// Do some operation or other on the fixed-size contents of each
pair[0] += 1;
pair[1] -= 1;
}
// Go forth and foo the foo_pairs
}
If this is happening inside a small function, it's okay in my book. Either way, you were going to end up with a transformed value of identical type as the same one, so copying the whole thing first and then mutating is about the same amount of effort as referencing a value in a closure and returning some function of it.
Note that this only works if you plan to compute something that is going to be the same type, up to and including size/length. But that's implied by your use of Rust arrays. (Specifically, you could Value() your Foos or Nothing them as you like, and still be within type parameters for your array.)

How can I check, at compile-time, that a slice is a specific size?

I'd like to check, at compile-time, that a slice used in a From implementation is a specific size.
(Playground)
#[derive(Debug)]
struct Pixel {
r: u8,
g: u8,
b: u8,
}
impl From<&[u8]> for Pixel {
fn from(arr: &[u8]) -> Pixel {
Pixel {
r: arr[0],
g: arr[1],
b: arr[2],
}
}
}
fn main() {
println!("Hello, world!");
let arr: [u8; 9] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let pixels: Vec<Pixel> = arr.chunks_exact(3).map(Pixel::from).collect();
println!("{:.?}", pixels);
}
This is not as specific as I'd like. I'd like to check the arr passed to Pixel::from<&[u8]>() is 3 elements as clearly as possible (at compile time).
Thought of assert!(arr.len()==3), but this checks at runtime.
So I thought maybe I could do the conversion by (Playground):
impl From<[u8; 3]> for Pixel {
fn from(arr: [u8; 3]) -> Pixel {
Pixel {
r: arr[0],
g: arr[1],
b: arr[2],
}
}
}
but this leads to:
error[E0277]: the trait bound `Pixel: From<&[u8]>` is not satisfied
--> src/main.rs:22:30
|
22 | let pixels: Vec<Pixel> = arr.chunks_exact(3).map(Pixel::from).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<&[u8]>` is not implemented for `Pixel`
|
= help: the following implementations were found:
<Pixel as From<[u8; 3]>>
error[E0277]: the trait bound `Pixel: From<&[u8]>` is not satisfied
--> src/main.rs:22:54
|
22 | let pixels: Vec<Pixel> = arr.chunks_exact(3).map(Pixel::from).collect();
| ^^^^^^^^^^^ the trait `From<&[u8]>` is not implemented for `Pixel`
|
= help: the following implementations were found:
<Pixel as From<[u8; 3]>>
= note: required by `from`
error[E0277]: the trait bound `Pixel: From<&[u8]>` is not satisfied
--> src/main.rs:22:30
|
22 | let pixels: Vec<Pixel> = arr.chunks_exact(3).map(Pixel::from).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<&[u8]>` is not implemented for `Pixel`
|
= help: the following implementations were found:
<Pixel as From<[u8; 3]>>
Similarly I tried From<&[u8; 3]> but same result.
Is there a way to implement from for a specific sized slice?
This is a not a duplicate of How to convert a slice into an array reference? as this question specifically relates to checking at compile-time without runtime performance effects, it is not casting &[u8] to &[u8; 3] rather simply checking at compile time &[u8] has 3 elements (which may be done via using &[u8; 3]). All answers to the aforementioned question incur runtime affects, except I believe this approach in this answer (applied like this) but this does not check at all that the slice is the appropriate length. This question is not specifically about being able to use Pixel::from<[u8;3]> but rather about generally checking the length at compile time, which none of these answers offer or relate to.
You cannot do this at compile time because slice lengths are not known at compile time. That's a big reason that slices exist in the first place. When the length is known at compile time, that's an array.
See also:
What is the difference between a slice and an array?
How to set a Rust array length dynamically?
Take slice of certain length known at compile time
I'd instead write both fallible and infallible conversions:
use std::array::TryFromSliceError;
use std::convert::TryFrom;
#[derive(Debug)]
struct Pixel {
r: u8,
g: u8,
b: u8,
}
impl TryFrom<&[u8]> for Pixel {
type Error = TryFromSliceError;
fn try_from(arr: &[u8]) -> Result<Self, Self::Error> {
<&[u8; 3]>::try_from(arr).map(Self::from)
}
}
impl From<&[u8; 3]> for Pixel {
fn from(arr: &[u8; 3]) -> Self {
Self::from(*arr)
}
}
impl From<[u8; 3]> for Pixel {
fn from(arr: [u8; 3]) -> Self {
Pixel {
r: arr[0],
g: arr[1],
b: arr[2],
}
}
}
Then you can convert from an array, allowing for a compile time error, or when you have a slice and don't know the length at compile time, you can attempt to convert and have a run-time error.
In the future, you can use methods like slice::array_chunks to convert a slice into an iterator of arrays. However, there's still the case that the slice wasn't the right length (too long or short) that you have to handle somehow.

How do I compare a vector against a reversed version of itself?

Why won't this compile?
fn isPalindrome<T>(v: Vec<T>) -> bool {
return v.reverse() == v;
}
I get
error[E0308]: mismatched types
--> src/main.rs:2:25
|
2 | return v.reverse() == v;
| ^ expected (), found struct `std::vec::Vec`
|
= note: expected type `()`
found type `std::vec::Vec<T>`
Since you only need to look at the front half and back half, you can use the DoubleEndedIterator trait (methods .next() and .next_back()) to look at pairs of front and back elements this way:
/// Determine if an iterable equals itself reversed
fn is_palindrome<I>(iterable: I) -> bool
where
I: IntoIterator,
I::Item: PartialEq,
I::IntoIter: DoubleEndedIterator,
{
let mut iter = iterable.into_iter();
while let (Some(front), Some(back)) = (iter.next(), iter.next_back()) {
if front != back {
return false;
}
}
true
}
(run in playground)
This version is a bit more general, since it supports any iterable that is double ended, for example slice and chars iterators.
It only examines each element once, and it automatically skips the remaining middle element if the iterator was of odd length.
Read up on the documentation for the function you are using:
Reverse the order of elements in a slice, in place.
Or check the function signature:
fn reverse(&mut self)
The return value of the method is the unit type, an empty tuple (). You can't compare that against a vector.
Stylistically, Rust uses 4 space indents, snake_case identifiers for functions and variables, and has an implicit return at the end of blocks. You should adjust to these conventions in a new language.
Additionally, you should take a &[T] instead of a Vec<T> if you are not adding items to the vector.
To solve your problem, we will use iterators to compare the slice. You can get forward and backward iterators of a slice, which requires a very small amount of space compared to reversing the entire array. Iterator::eq allows you to do the comparison succinctly.
You also need to state that the T is comparable against itself, which requires Eq or PartialEq.
fn is_palindrome<T>(v: &[T]) -> bool
where
T: Eq,
{
v.iter().eq(v.iter().rev())
}
fn main() {
println!("{}", is_palindrome(&[1, 2, 3]));
println!("{}", is_palindrome(&[1, 2, 1]));
}
If you wanted to do the less-space efficient version, you have to allocate a new vector yourself:
fn is_palindrome<T>(v: &[T]) -> bool
where
T: Eq + Clone,
{
let mut reverse = v.to_vec();
reverse.reverse();
reverse == v
}
fn main() {
println!("{}", is_palindrome(&[1, 2, 3]));
println!("{}", is_palindrome(&[1, 2, 1]));
}
Note that we are now also required to Clone the items in the vector, so we add that trait bound to the method.

Is there a good way to convert a Vec<T> to an array?

Is there a good way to convert a Vec<T> with size S to an array of type [T; S]? Specifically, I'm using a function that returns a 128-bit hash as a Vec<u8>, which will always have length 16, and I would like to deal with the hash as a [u8, 16].
Is there something built-in akin to the as_slice method which gives me what I want, or should I write my own function which allocates a fixed-size array, iterates through the vector copying each element, and returns the array?
Arrays must be completely initialized, so you quickly run into concerns about what to do when you convert a vector with too many or too few elements into an array. These examples simply panic.
As of Rust 1.51 you can parameterize over an array's length.
use std::convert::TryInto;
fn demo<T, const N: usize>(v: Vec<T>) -> [T; N] {
v.try_into()
.unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len()))
}
As of Rust 1.48, each size needs to be a specialized implementation:
use std::convert::TryInto;
fn demo<T>(v: Vec<T>) -> [T; 4] {
v.try_into()
.unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", 4, v.len()))
}
As of Rust 1.43:
use std::convert::TryInto;
fn demo<T>(v: Vec<T>) -> [T; 4] {
let boxed_slice = v.into_boxed_slice();
let boxed_array: Box<[T; 4]> = match boxed_slice.try_into() {
Ok(ba) => ba,
Err(o) => panic!("Expected a Vec of length {} but it was {}", 4, o.len()),
};
*boxed_array
}
See also:
How to get a slice as an array in Rust?
How do I get an owned value out of a `Box`?
Is it possible to control the size of an array using the type parameter of a generic?

How to pass an owned array by reference

I'm just playing around with rust for the first time, implementing quicksort, and I'm stuck on references to dynamically sized arrays (I had no problem with fixed size arrays).
I would like to have an indefinitely sized array of integers to sort, which I gather I can create with something like:
let array = ~[1,2,3,4,3,2,1];
However, I am not sure how I can pass this by reference into a partition function.
partition ( a : &mut ~[uint], p: uint, i: uint) {
// partition a, in place
}
As soon as I try to reorder any elements in a, the compiler complains:
error: cannot assign to immutable vec content a[..]
You should use a mutable borrow of the vector rather than a mutable borrow of a pointer to a vector, so you should get rid of that ~ pointer in the type of your partition function. For example:
fn partition(_: &mut [uint], _: uint, _: uint) { }
fn main() {
let mut array = ~[1, 2, 3, 4, 3, 2, 1];
partition(array, 0, 0);
}
Notice that array is automatically passed as a mutable borrowed pointer.
If you use a Vec instead, then you need to explicitly create a slice:
fn partition(_: &mut [uint], _: uint, _: uint) { }
fn main() {
let mut array = vec!(1, 2, 3, 4, 3, 2, 1);
partition(array.as_mut_slice(), 0, 0);
}
Both code snippets should compile on the latest Rust (from tip).
With 0.10 the language is undergoing some changes to array types at the moment, so things are a bit messy. Vec<T> is Rust's intended dynamically sized array type.
let vec = vec!(1u,2,3,4,3,2,1);
partition ( a : &mut Vec<uint>, p: uint, i: uint) {
// partition a, in place
}
Note that indexing of a Vec via brackets is currently only possible by first calling .as_slice() or .as_mut_slice() on it since the respective traits are not yet implemented.

Resources