Rust: Creating a slice from a reference - rust

Is it possible to create a slice of an array (or anything else) using references into that array to specify the start/end rather than indices?
For example, say I am iterating through an array, and when I get to a certain element I want to call a function passing a slice of the array from the current element to the end:
let list = [1, 2, 3, 4, 5, 6];
for item in &list {
if passes_test(item) {
process_remainder(&list[item..]); // does not compile
}
}
Coming from C this seems like a natural thing to want to do - a reference is just a pointer, and a slice is just a pair of pointers (or pointer and length), and taking multiple references should be fine since none of them are mutable. But I can't find right syntax to do it.
Alternately, is it possible to get the index for a given reference (like with pointer arithmetic in C), or do I just need to break down and use enumerate to generate both index and reference as I iterate?

Usually, enumerate is preferred over pointer arithmetic.
fn main() {
let list = [1i32, 2, 3, 4, 5, 6];
for (index, item) in list.iter().enumerate() {
if *item > 5 {
process_remainder(&list[index..]);
}
}
}
(Accidentally, your code does compile since array items are usize. :) So I changed them to i32.)

You can do it, but it's neither safe nor pretty:
let list = [1, 2, 3, 4, 5, 6];
for item in &list {
if passes_test(item) {
let idx = unsafe { (item as *const u64).offset_from(list.as_ptr()) as usize };
process_remainder(&list[idx..]);
}
}
Using enumerate is a better option:
let list = [1, 2, 3, 4, 5, 6];
for (i, item) in list.iter().enumerate() {
if passes_test(item) {
process_remainder(&list[i..]);
}
}

Related

How to compare the value of next element with the current element in an iterator without a loop and for_each?

I have a vector like [1, 2, 4, 3], I want to remove 3 because 3 is smaller than 4.
I want to use the iterator to solve this problem, and do not use the loop or for_each.
The first step I think need to do is vec.into_iter, but I don't know what to do next.
To reformulate, you want to remove any element smaller than the previous element.
Let's write a function to do so. As you want to work exclusively with iterators, therefore in a functional style, we are going to assume the input vector is immutable, so the function should take a slice as input, and return a new Vec:
fn remove_smaller<T: Ord + Copy>(v: &[T]) -> Vec<T> {
v.iter()
.rev()
.collect::<Vec<_>>()
.windows(2)
.filter(|a| a[0] > a[1])
.map(|a| *a[0])
.chain([v[0]])
.rev()
.collect()
}
Let's explain what this function is doing, using vec![1, 2, 4, 3] as sample input.
We first reverse the order of the vector so we can operate on windows looking at the previous value, and collect it into a new vector (needed as windows is implemented for slices only).
&[3, 4, 2, 1]
windows(2) returns an iterator that will yield overlapping pairs of elements of the slice, except the last element, which has no next:
&[3, 4], &[4, 2], &[2, 1]
We then filter with filter(|a| a[0] > a[1]) meaning we only keep entries which are ordered (hence why type of input needs to be Ord):
&[4, 2], &[2, 1]
We then map with map(|a| *a[0]) in order to keep each value, which needs T to be Copy:
4, 2
Now, since we are missing the first element of the input array, we need to add it again, using .chain([v[0]]) giving us:
4, 2, 1
We then reverse the iterator to obtain the output array in correct order:
1, 2, 4
See it in action in the playground.
This is not a very efficient method to achieve the result, as it needs to allocate twice as much memory as the input.
You can use the zip and skip functionality to put together two elements of an array.
Following the footsteps of #sirdarius, Here is how your function can be:
fn remove_smaller<T: Ord + Copy>(v: &[T]) -> Vec<T> {
let mut res = vec![v[0]];
res.extend(
v.iter()
.zip(v.iter().skip(1))
.filter(|(a, b)| a < b)
.map(|(_, b)| *b),
);
res
}
Walk through:
We fist create our result vector and push the first element in it since it is always in the answer vector.
Then we extend our result vector by another iterator which would perform the following:
create a tuple for each element of the array with indices of the same array but one index ahead (v.iter().skip(1)).
we then filter out pairs which meet our ordering and finally, we map the pair to a single value.
There is an iterator only way to do what you wanted in O(1) space.
fn non_decreasing(v: Vec<i32>) -> Vec<i32> {
if v.is_empty() {
return v;
}
let first = v[0];
once(first)
.chain(
v.into_iter()
.skip(1)
.scan(first, |last_max, cur_elem| {
if cur_elem < *last_max {
Some(None)
} else {
*last_max = cur_elem;
Some(Some(cur_elem))
}
})
.flatten(),
)
.collect()
}
This function will not use any extra space (even for the output, on newer rustc versions). It will return a vector that's non-decreasing. That is, each element in the result vector will be >= the previous one.
If you wanted to compare the elements only to the previous element and not the previous largest, then just add the *last_max = cur_elem line to the if branch as well.

How to just continue if an array index is out of range?

Let's say that I have this array - [1, 2, 3, 4, 5] - and I try to access an index that doesn't exist (Let's say 6). It would normally through an error. But is there any way that I can just completely ignore that error and continue like nothing happened?
Arrays ([T; N] with a fixed size N known at compile time) can be freely coerced into slices ([T] with a variable length known at runtime), so when you have an array you have access to the wide array of slice methods.
For your use case, slice::get returns an Option<T>. If the index is valid you get Some(value), and if it's invalid you get None.
Example:
let array = [1, 2, 3, 4, 5];
let index = 6;
if let Some(value) = array.get(index) {
println!("Found {} at array[{}]", value, index);
}
else {
println!("array[{}] is out of bounds", index);
}
Output:
array[6] is out of bounds
Playground
If the array index is negative, you will get a compile time error because it have to be of type usize.
If its positive, you could compare it with the length of the array.
To handle an out of bounds index (like 6 in this case), you could do something like:
fn get_item(input_array: &[i8; 5], index: usize) -> i8 {
if index >= input_array.len() {
-1
} else { // continue
input_array[index]
}
}
#[test]
fn test_get_item() {
assert_eq!(get_item(&[1, 2, 3, 4, 5], 2), 3, "Value at index 2 is 3");
}
#[test]
fn test_get_item_out_of_bounds() {
assert_eq!(
get_item(&[1, 2, 3, 4, 5], 6),
-1,
"Array index out of bounds"
);
}

How to copy to slice with different size in Rust? [duplicate]

If I have two arrays of different sizes:
let mut array1 = [0; 8];
let array2 = [1, 2, 3, 4];
How would I copy array2 into the first 4 bytes of array1? I can take a mutable 4 byte slice of array1, but I'm not sure how or if I can assign into it.
Manually one can do
for (dst, src) in array1.iter_mut().zip(&array2) {
*dst = *src
}
for a typical slice. However, there is a likely faster specialization in clone_from_slice:
dst[..4].clone_from_slice(&src)
A slightly older method is to use std::io::Write, which was implemented for &mut [u8].
use std::io::Write;
let _ = dst.write(&src)
This will write up to the end of dst and return how many values were written in a Result. If you use write_all, this will return an Err if not all bytes could be written.
The most flexible way is to use iterators to handle each element successively:
for (place, data) in array1.iter_mut().zip(array2.iter()) {
*place = *data
}
.mut_iter creates an Iterator that yields &mut u8, that is, mutable references pointing into the slice/array. iter does the same but with shared references. .zip takes two iterators and steps over them in lock-step, yielding the elements from both as a tuple (and stops as soon as either one stops).
If you need/want to do anything 'fancy' with the data before writing to place this is the approach to use.
However, the plain copying functionality is also provided as single methods,
.copy_from, used like array1.copy_from(array2).
std::slice::bytes::copy_memory, although you will need to trim the two arrays because copy_memory requires they are the same length:
use std::cmp;
use std::slice::bytes;
let len = cmp::min(array1.len(), array2.len());
bytes::copy_memory(array1.mut_slice_to(len), array2.slice_to(len));
(If you know that array1 is always longer than array2 then bytes::copy_memory(array1.mut_slice_to(array2.len()), array2) should also work.)
At the moment, the bytes version optimises the best, down to a memcpy call, but hopefully rustc/LLVM improvements will eventually take them all to that.
You could simply use copy_from_slice() and use Range & Co:
fn main() {
let mut dest = [0; 8];
let src = [1, 2, 3, 4];
dest[..4].copy_from_slice(&src);
assert_eq!(dest, [1, 2, 3, 4, 0, 0, 0, 0]);
}
Inverse case:
fn main() {
let src = [1, 2, 3, 4, 5, 6, 7, 8];
let mut dest = [0; 4];
dest.copy_from_slice(&src[2..6]);
assert_eq!(dest, [3, 4 ,5, 6]);
}
Combined case:
fn main() {
let src = [1, 2, 3, 4, 5, 6, 7, 8];
let mut dest = [0; 4];
dest[1..3].copy_from_slice(&src[3..5]);
assert_eq!(dest, [0, 4, 5, 0]);
}

Implementing PHP array_column in Rust

I'm in the process of learning Rust, but I could not find an answer to this question.
In PHP, there's the array_column method and it works this way:
given an array of arrays (this would be a a Vector of vectors in Rust):
$records = [
[1,2,3],
[1,2,3],
[1,2,3],
[1,2,3]
];
if I want to get an array containing all the first elements (a "column") of the inner arrays I can do:
$column = array_column($records, 0);
This way, for example, I get [1,1,1,1]. If I change that 0 with 1, I get [2,2,2,2] and so on.
Since there's no array_column equivalent in Rust (that is: I could not find it), what could be the best way to implement a similar behavior with a vector of vectors?
I decided to play with iterators, as you tried in the comments.
This version works with any clonable values (numbers included). We iterate over subvectors, and for each we call a get method, which either yields an element of the vector Some(&e) or None if we ask out of bounds.
and_then then accepts a value from get, and if it was None, then None is returned, otherwise, if it's Some(&e) then Some(e.clone()) is returned, i.e. we clone the value (because we only have the reference to the value from get, we can't store it, we have to copy the value).
collect then works with Iter<Option<T>>, and it conveniently turns it in Option<Vec<T>>, i.e. it returns None if some Nones were in the iterator (which means some arrays didn't have big enough size), or returns Some(Vec<T>), if everything is fine.
fn main() {
let array = vec![
vec![1, 2, 3, 4],
vec![1, 2, 3, 4, 5],
vec![1, 2, 3, 4],
vec![1, 2, 3, 4],
];
let ac = array_column(&array, 0);
println!("{:?}", ac); // Some([1, 1, 1, 1])
let ac = array_column(&array, 3);
println!("{:?}", ac); // Some([4, 4, 4, 4])
let ac = array_column(&array, 4); // None
println!("{:?}", ac);
}
fn array_column<T: Clone>(array: &Vec<Vec<T>>, column: usize) -> Option<Vec<T>> {
array.iter()
.map( |subvec| subvec.get(column).and_then(|e| Some(e.clone())) )
.collect()
}
Alex version is good, but you can generalize it using references too, so there will be no need for the item to be Clone:
fn array_column<'a, T>(array: &'a Vec<Vec<T>>, column: usize) -> Option<Vec<&'a T>> {
array.iter()
.map( |subvec| subvec.get(column) )
.collect()
}
Playground

How to remove an element from a vector given the element?

Is there a simple way to remove an element from a Vec<T>?
There's a method called remove(), and it takes an index: usize, but there isn't even an index_of() method that I can see.
I'm looking for something (hopefully) simple and O(n).
This is what I have come up so far (that also makes the borrow checker happy):
let index = xs.iter().position(|x| *x == some_x).unwrap();
xs.remove(index);
I'm still waiting to find a better way to do this as this is pretty ugly.
Note: my code assumes the element does exist (hence the .unwrap()).
You can use the retain method but it will delete every instance of the value:
fn main() {
let mut xs = vec![1, 2, 3];
let some_x = 2;
xs.retain(|&x| x != some_x);
println!("{:?}", xs); // prints [1, 3]
}
Your question is under-specified: do you want to return all items equal to your needle or just one? If one, the first or the last? And what if there is no single element equal to your needle? And can it be removed with the fast swap_remove or do you need the slower remove? To force programmers to think about those questions, there is no simple method to "remove an item" (see this discussion for more information).
Remove first element equal to needle
// Panic if no such element is found
vec.remove(vec.iter().position(|x| *x == needle).expect("needle not found"));
// Ignore if no such element is found
if let Some(pos) = vec.iter().position(|x| *x == needle) {
vec.remove(pos);
}
You can of course handle the None case however you like (panic and ignoring are not the only possibilities).
Remove last element equal to needle
Like the first element, but replace position with rposition.
Remove all elements equal to needle
vec.retain(|x| *x != needle);
... or with swap_remove
Remember that remove has a runtime of O(n) as all elements after the index need to be shifted. Vec::swap_remove has a runtime of O(1) as it swaps the to-be-removed element with the last one. If the order of elements is not important in your case, use swap_remove instead of remove!
There is a position() method for iterators which returns the index of the first element matching a predicate. Related question: Is there an equivalent of JavaScript's indexOf for Rust arrays?
And a code example:
fn main() {
let mut vec = vec![1, 2, 3, 4];
println!("Before: {:?}", vec);
let removed = vec.iter()
.position(|&n| n > 2)
.map(|e| vec.remove(e))
.is_some();
println!("Did we remove anything? {}", removed);
println!("After: {:?}", vec);
}
Is drain_filter() new from the last answers?
Seems similar to Kai's answer:
#![feature(drain_filter)]
let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
assert_eq!(numbers, vec![1, 3, 5, 9, 11, 13, 15]);
https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain_filter
If your data is sorted, please use binary search for O(log n) removal, which could be much much faster for large inputs.
match values.binary_search(value) {
Ok(removal_index) => values.remove(removal_index),
Err(_) => {} // value not contained.
}

Resources