I want to get the size of all dimensions of an array in Rust but I'm not sure how to go about this. I'm able to get the length of the array using x.len() but I need to somehow do this recursively.
I want to be able to do something like this:
let x = [[1, 2, 3], [4, 5, 6]];
println!("{:?}", x.dimensions());
// [2, 3]
A slice with a shape like [[1], [2, 3], [4, 5, 6]] should give an error.
It's not possible to do this in a generic fashion for every possible depth of nesting. Rust is a statically typed language, so you have to know your input and output types. What is an input type for [1] and what is the input type for [[1]]? Likewise, what are the corresponding output types?
The closest I know of is a trait with an associated type. This allows implementing it for a specific type which then associates another output type:
trait Thing {
type Dimensions;
fn thing(self) -> Self::Dimensions;
}
However, as soon as you implement it, you run into problems:
impl<'a, T> Thing for &'a[T] {
type Dimensions = usize;
fn thing(self) -> usize {
self.len()
}
}
impl<'a, T> Thing for &'a[&'a[T]] {
type Dimensions = [usize; 2];
fn thing(self) -> Self::Dimensions {
[self.len(), self[0].len()]
}
}
error[E0119]: conflicting implementations of trait `Thing` for type `&[&[_]]`:
--> src/main.rs:14:1
|
6 | impl<'a, T> Thing for &'a[T] {
| - first implementation here
...
14 | impl<'a, T> Thing for &'a[&'a[T]] {
| ^ conflicting implementation for `&[&[_]]`
That's because a &[[T]] is a &[T].
You may also think to try something recursive, but there's no way to say &[T] and know if T can be further iterated or not. If you had an HasLength trait and a DoesntHaveLength trait, nothing stops you from implementing both traits for a single type. Thus, you are stopped again.
Here's one partial attempt at using specialization:
#![feature(specialization)]
trait Dimensions: Sized {
fn dimensions(self) -> Vec<usize> {
let mut answers = vec![];
self.dimensions_core(&mut answers);
answers
}
fn dimensions_core(self, &mut Vec<usize>);
}
impl<'a, T> Dimensions for &'a [T] {
default fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(self.len());
}
}
impl<'a, T> Dimensions for &'a [T]
where T: Dimensions + Copy
{
fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(self.len());
self[0].dimensions_core(answers);
}
}
impl<'a, T> Dimensions for [T; 2] {
default fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(2)
}
}
impl<'a, T> Dimensions for [T; 2]
where T: Dimensions + Copy
{
fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(2);
self[0].dimensions_core(answers);
}
}
impl<'a, T> Dimensions for [T; 3] {
default fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(3)
}
}
impl<'a, T> Dimensions for [T; 3]
where T: Dimensions + Copy
{
fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(3);
self[0].dimensions_core(answers);
}
}
// Also implement for all the other sizes of array as well as `Vec`
fn main() {
let x = [[1, 2, 3], [4, 5, 6]];
println!("{:?}", x.dimensions());
let x = [[1, 2], [3, 4], [5, 6]];
println!("{:?}", x.dimensions());
}
It has the obvious downside that you still have to implement the trait for each array size in order to get specialization to kick in.
I'm guessing that you are coming from a language that is highly dynamic. Different languages have different strengths and weaknesses. In Rust, you know your input types, so there's no way the function wouldn't know the nesting of my type. If it's going to receive a Vec<T> or a Vec<&[Vec<T>]>, I will know the depth of nesting ahead of time, so I can write a function that returns the lengths of each one:
fn depth3<A, B, C, T>(a: A) -> [usize; 3]
where A: AsRef<[B]>,
B: AsRef<[C]>,
C: AsRef<[T]>
{
let a = a.as_ref();
// All of these should check that the length is > 1
// and possibly that all children have same length
let b = a[0].as_ref();
let c = b[0].as_ref();
[a.len(), b.len(), c.len()]
}
fn main() {
let x = [[[1], [2], [3]], [[4], [5], [6]]];
println!("{:?}", depth3(&x));
}
This function is as generic as I think it can be - you pass in references to arrays, slices, vectors, or direct values for those types. In fact, I can't think of a way to even define a slice/vector/array with an unknown depth. I think to do something like that you'd have to introduce some new type (likely an enum) with some indirection so that you could have a non-infinite size.
An array is defined as [T], T can't be both [U; 2] and [U; 3]. This means that you wouldn't even be able to get past compilation with this.
If you instead used a Vec<Vec<T>> as #Shepmaster hints, you could do something like this.
fn main() {
let x = vec![vec![1, 2, 3], vec![4, 5]];
println!("{:?}", get_2d_dimension(&x));
}
fn get_2d_dimension<T>(arr: &[Vec<T>]) -> Result<(usize, usize), &str> {
let rows = arr.len();
if rows <= 1 {
return Err("Not 2d");
}
let cols = arr[0].len();
if arr.iter().skip(1).filter(|v| v.len() == cols).count() != rows - 1 {
Err("Not square.")
} else {
Ok((rows, cols))
}
}
As others have noted, finding the dimensions of a "vanilla" nested list is impossible. However, you can choose to implement a custom nested list data structure, like so:
#[derive(Clone, Debug)]
pub enum NestedList<S>
where S: Clone
{
Integer(S),
Array(Vec<NestedList<S>>)
}
Then you'd have to rewrite your nested list using NestedList:
use NestedList::Integer as i;
use NestedList::Array as a;
fn main() {
let array = a(vec![
a(vec![i(1), i(2), i(3)]),
a(vec![i(4), i(5), i(6)])
]);
}
from which you can find the dimensions. Here is an implementation of this method. It is very verbose, but I hope this is what you were looking for?
Related
In my project I'm frequently iterating through a vector of structs to find an object by some field value, then use some trait function on that object:
pub struct Person{
name: String,
age: u32,
id: u32,
}
impl Person{
pub fn new(name: String, id_num: u32, age: u32)->Self{
let p = Person{
name: name,
id: id_num,
age: age,
};
p
}
}
trait PersonTrait{
fn printname();
fn get_name()->String;
fn get_age()->u32;
fn set_age(age: u32);
}
impl PersonTrait for Person{
fn printname(){
dbg!(self.name)
}
fn get_name()->String{
self.name
}
fn get_id()->u32{
self.id;
}
fn set_age(age: u32){
self.age = age;
}
}
fn main(){
let my_people = vec![Person::new("Rakim".to_string(), 1, 56), Person::new("Ghostface".to_string(), 2, 56), Person::new("RZA".to_string(), 3, 56)];
//frequently repeating this pattern of finding struct in array of structs, then doing something to that found struct
for person in my_people.clone(){
if person.get_id() == 1 {
person.set_age(100);
}
}
for person in my_people.clone(){
if person.get_id() == "Rakim".to_string(){
person.printname();
}
}
}
So the general pattern im using here is:
for x in my_objects{
if x.id() == some_id{
x.do_some_trait_function()
}
}
I'd like to create a more general function to make this syntax simpler, something like:
//not sure what the correct syntax would be here, or how you might pass a trait function as an argument
fn find_then_do_trait_function(obj_list: Vec<Person>, id: u32, trait_function: my_trait_function()){
for x in obj_list(){
if x.get_id() == id {
//use my trait function on x
}
}
}
How might I do this? I know I could create an enum for every trait function, then match that enum, but that also seems pretty verbose.
There's nothing unique about trait functions. You've identified a very common pattern which can be split into two pieces: we want to filter a vector and then perform some operation on each matching element. We can define a function that takes two closure arguments to do this for us.
fn search_and_call<T>(obj_list: &mut Vec<T>,
mut condition: impl FnMut(&mut T) -> bool,
mut func: impl FnMut(&mut T) -> ()) {
for x in obj_list {
if condition(x) {
func(x);
}
}
}
func can be any closure. That closure might call a trait function, or it might print to the screen, or do any number of things. The writer of the above function needn't care; it's all the same as far as we're concerned. Sample usage:
let mut v = vec!(1, 2, 3, 4);
search_and_call(&mut v, |x| *x % 2 == 0, |x| println!("{}", *x));
It's worth noting, however, that Rust's excellent Iterator trait defines a ton of useful functions, and we can get this behavior for free, without even touching a for loop.
let mut v = vec!(1, 2, 3, 4);
v.iter().filter(|x| *x % 2 == 0).for_each(|x| println!("{}", *x));
.iter() gets an iterator over our vector, .filter(...) produces a new iterator that selects certain elements based on our condition, and .for_each(...) calls a function on all elements which remain after the filter.
I want to implement an iterator for the struct with an array as one of its fields. The iterator should return a slice of that array, but this requires a lifetime parameter. Where should that parameter go?
The Rust version is 1.37.0
struct A {
a: [u8; 100],
num: usize,
}
impl Iterator for A {
type Item = &[u8]; // this requires a lifetime parameter, but there is none declared
fn next(&mut self) -> Option<Self::Item> {
if self.num >= 10 {
return None;
}
let res = &self.a[10*self.num..10*(self.num+1)];
self.num += 1;
Some(res)
}
}
I wouldn't implement my own. Instead, I'd reuse the existing chunks iterator and implement IntoIterator for a reference to the type:
struct A {
a: [u8; 100],
num: usize,
}
impl<'a> IntoIterator for &'a A {
type Item = &'a [u8];
type IntoIter = std::slice::Chunks<'a, u8>;
fn into_iter(self) -> Self::IntoIter {
self.a.chunks(self.num)
}
}
fn example(a: A) {
for chunk in &a {
println!("{}", chunk.iter().sum::<u8>())
}
}
When you return a reference from a function, its lifetime needs to be tied to something else. Otherwise, the compiler wouldn't know how long the reference is valid (the exception to this is a 'static lifetime, which lasts for the duration of the whole program).
So we need an existing reference to the slices. One standard way to do this is to tie the reference to the iterator itself. For example,
struct Iter<'a> {
slice: &'a [u8; 100],
num: usize,
}
Then what you have works almost verbatim. (I've changed the names of the types and fields to be a little more informative).
impl<'a> Iterator for Iter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.num >= 100 {
return None;
}
let res = &self.slice[10 * self.num..10 * (self.num + 1)];
self.num += 1;
Some(res)
}
}
Now, you probably still have an actual [u8; 100] somewhere, not just a reference. If you still want to work with that, what you'll want is a separate struct that has a method to convert into A. For example
struct Data {
array: [u8; 100],
}
impl Data {
fn iter<'a>(&'a self) -> Iter<'a> {
Iter {
slice: &self.array,
num: 0,
}
}
}
Thanks to lifetime elision, the lifetimes on iter can be left out:
impl Data {
fn iter(&self) -> Iter {
Iter {
slice: &self.array,
num: 0,
}
}
}
(playground)
Just a few notes. There was one compiler error with [0u8; 100]. This may have been a typo for [u8; 100], but just in case, here's why we can't do that. In the fields for a struct definition, only the types are specified. There aren't default values for the fields or anything like that. If you're trying to have a default for the struct, consider using the Default trait.
Second, you're probably aware of this, but there's already an implementation of a chunk iterator for slices. If slice is a slice (or can be deref coerced into a slice - vectors and arrays are prime examples), then slice.chunks(n) is an iterator over chunks of that slice with length n. I gave an example of this in the code linked above. Interestingly, that implementation uses a very similar idea: slice.chunks(n) returns a new struct with a lifetime parameter and implements Iterator. This is almost exactly the same as our Data::iter.
Finally, your implementation of next has a bug in it that causes an out-of-bounds panic when run. See if you can spot it!
This question already has an answer here:
How can I add new methods to Iterator?
(1 answer)
Closed 4 years ago.
Let's say I want to double each value in an iterator of numbers. I could do this:
vec![1, 2, 3]
.into_iter()
.map(|x| x * 2)
.for_each(|x| println!("{}", x)); //Prints 2, 4, 6.
To get cleaner code, I would prefer to do this:
vec![1, 2, 3]
.into_iter()
.double() //I need to implement this.
.for_each(|x| println!("{}", x));
How do I write my own chainable iterator function, like double in this example? I guess I will have to create an interface and implement it for Iterator? There are a lot of types to get right, so a working solution for this silly example would be helpful.
First you have to create a new-type to implement your iterator. The simplest way is to wrap a iterator of the type you want to target:
struct Double<T: ?Sized> {
inner: T,
}
Now you just implement the Iterator trait for this type if the innert type T is of the correct type. Something like:
impl<T> Iterator for Double<T>
where T: Iterator<Item = i32> {
type Item = i32;
fn next(&mut self) -> Option<i32> {
self.inner.next().map(|x| 2*x)
}
}
And that's it! You just need to add a Double constructor. The most ergonomic solution is to extend Iterator. Something like this:
trait Doubler : Iterator<Item = i32> {
fn into_double(self) -> Double<Self>;
}
impl<T> Doubler for T
where T: Iterator<Item = i32> {
fn into_double(self) -> Double<Self> {
Double { inner: self }
}
}
An example of usage (playground):
fn main() {
vec![1, 2, 3]
.into_iter()
.into_double()
.for_each(|x| println!("{}", x));
}
I have an array of an unknown size, and I would like to get a slice of that array and convert it to a statically sized array:
fn pop(barry: &[u8]) -> [u8; 3] {
barry[0..3] // expected array `[u8; 3]`, found slice `[u8]`
}
How would I do this?
You can easily do this with the TryInto trait (which was stabilized in Rust 1.34):
// Before Rust 2021, you need to import the trait:
// use std::convert::TryInto;
fn pop(barry: &[u8]) -> [u8; 3] {
barry.try_into().expect("slice with incorrect length")
}
But even better: there is no need to clone/copy your elements! It is actually possible to get a &[u8; 3] from a &[u8]:
fn pop(barry: &[u8]) -> &[u8; 3] {
barry.try_into().expect("slice with incorrect length")
}
As mentioned in the other answers, you probably don't want to panic if the length of barry is not 3, but instead handle this error gracefully.
This works thanks to these impls of the related trait TryFrom (before Rust 1.47, these only existed for arrays up to length 32):
impl<'_, T, const N: usize> TryFrom<&'_ [T]> for [T; N]
where
T: Copy,
impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N]
impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N]
Thanks to #malbarbo we can use this helper function:
use std::convert::AsMut;
fn clone_into_array<A, T>(slice: &[T]) -> A
where
A: Default + AsMut<[T]>,
T: Clone,
{
let mut a = A::default();
<A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
a
}
to get a much neater syntax:
fn main() {
let original = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let e = Example {
a: clone_into_array(&original[0..4]),
b: clone_into_array(&original[4..10]),
};
println!("{:?}", e);
}
as long as T: Default + Clone.
If you know your type implements Copy, you can use this form:
use std::convert::AsMut;
fn copy_into_array<A, T>(slice: &[T]) -> A
where
A: Default + AsMut<[T]>,
T: Copy,
{
let mut a = A::default();
<A as AsMut<[T]>>::as_mut(&mut a).copy_from_slice(slice);
a
}
Both variants will panic! if the target array and the passed-in slice do not have the same length.
I recommend using the crate arrayref, which has a handy macro for doing just this.
Note that, using this crate, you create a reference to an array, &[u8; 3], because it doesn't clone any data!
If you do want to clone the data, then you can still use the macro, but call clone at the end:
#[macro_use]
extern crate arrayref;
fn pop(barry: &[u8]) -> &[u8; 3] {
array_ref!(barry, 0, 3)
}
or
#[macro_use]
extern crate arrayref;
fn pop(barry: &[u8]) -> [u8; 3] {
array_ref!(barry, 0, 3).clone()
}
You can manually create the array and return it.
Here is a function that can easily scale if you want to get more (or less) than 3 elements.
Note that if the slice is too small, the end terms of the array will be 0's.
fn pop(barry: &[u8]) -> [u8; 3] {
let mut array = [0u8; 3];
for (&x, p) in barry.iter().zip(array.iter_mut()) {
*p = x;
}
array
}
Here's a function that matches the type signature you asked for.
fn pop(barry: &[u8]) -> [u8; 3] {
[barry[0], barry[1], barry[2]]
}
But since barry could have fewer than three elements, you may want to return an Option<[u8; 3]> rather than a [u8; 3].
fn pop(barry: &[u8]) -> Option<[u8; 3]> {
if barry.len() < 3 {
None
} else {
Some([barry[0], barry[1], barry[2]])
}
}
I was unhappy with other answers because I needed several functions that return varying length fixed u8 arrays. I wrote a macro that produces functions specific for the task. Hope it helps someone.
#[macro_export]
macro_rules! vec_arr_func {
($name:ident, $type:ty, $size:expr) => {
pub fn $name(data: std::vec::Vec<$type>) -> [$type; $size] {
let mut arr = [0; $size];
arr.copy_from_slice(&data[0..$size]);
arr
}
};
}
//usage - pass in a name for the fn, type of array, length
vec_arr_func!(v32, u8, 32);
v32(data); //where data is std::vec::Vec<u8>
The nice common thing between Vec, 'Slice' and Array is Iter, so you can zip and map both together, as simple as:
let x = vec![1, 2, 3];
let mut y: [u8; 3] = [Default::default(); 3];
println!("y at startup: {:?}", y);
x.iter().zip(y.iter_mut()).map(|(&x, y)| *y = x).count();
println!("y copied from vec: {:?}", y);
This is as the array is 1 dimensional array.
To test all together, vec, slice and array, here you go:
let a = [1, 2, 3, 4, 5];
let slice = &a[1..4];
let mut x: Vec<u8> = vec![Default::default(); 3];
println!("X at startup: {:?}", x);
slice.iter().zip(x.iter_mut()).map(|(&s, x)| *x = s).count();
println!("X copied from vec: {:?}", x);
Another option which should be faster than byte-by-byte copy is:
y[..x.len()].copy_from_slice(&x);
Which is applicable for all, below is example:
let a = [1, 2, 3, 4, 5];
let mut b: Vec<u8> = vec![Default::default(); 5];
b[..a.len()].copy_from_slice(&a);
println!("Copy array a into vector b: {:?}", b);
let x: Vec<u8> = vec![1, 2, 3, 4, 5];
let mut y: [u8; 5] = [Default::default(); 5];
y[..x.len()].copy_from_slice(&x);
println!("Copy vector x into array y: {:?}", y);
I can create an array from a tuple like this:
let a = (1, 2, 3);
let b = [a.0, a.1, a.2];
Is there a way to do it without naming each element of the tuple? Something like:
let b = a.to_array();
There is no such functionality at the moment, however it would be perfectly possible to extend the set of implementations of the From trait to cover this usecase (and its reverse).
This extension would have to be in the core crate because of the orphan rules, but we can readily demonstrate it with custom traits:
use std::convert::Into;
trait MyFrom<T> {
fn my_from(t: T) -> Self;
}
trait MyInto<U> {
fn my_into(self) -> U;
}
impl<T, U> MyInto<U> for T
where
U: MyFrom<T>
{
fn my_into(self) -> U { <U as MyFrom<T>>::my_from(self) }
}
impl<T> MyFrom<()> for [T; 0] {
fn my_from(_: ()) -> Self { [] }
}
impl<T, A> MyFrom<(A,)> for [T; 1]
where
A: Into<T>,
{
fn my_from(t: (A,)) -> Self { [t.0.into()] }
}
impl<T, A, B> MyFrom<(A, B)> for [T; 2]
where
A: Into<T>,
B: Into<T>,
{
fn my_from(t: (A, B)) -> Self { [t.0.into(), t.1.into()] }
}
Once define, it's easy enough to use:
fn main() {
{
let array: [i64; 0] = ().my_into();
println!("{:?}", array);
}
{
let array: [i64; 1] = (1u32,).my_into();
println!("{:?}", array);
}
{
let array: [i64; 2] = (1u32, 2i16).my_into();
println!("{:?}", array);
}
}
will print:
[]
[1]
[1, 2]
The reverse implementation would be as easy, there's nothing mysterious here it's just boilerplate (hurray for macros!).
No, there isn't. What is more, you can't even iterate over tuples. The tuple is heterogeneous, so it's unfit for a conversion to a homogeneous type like a vector or an array.
You could write a macro to allow iteration over the contents of a tuple of a generic length and collect them (as long as all its elements are of the same type), but you would still have to access/process every element individually.