Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to unpack an iterator into a tuple?

Tags:

rust

Is there any way to accomplish something like the following:

let v = vec![1, 2, 3];
let (a, b) = v.iter().take(2);

Such that a = 1 and b = 2 at the end?

I know I could just use a vector but I would like to have named variables.

like image 304
anderspitman Avatar asked Apr 08 '15 02:04

anderspitman


People also ask

What is unpacking a tuple?

Unpacking a tuple means splitting the tuple's elements into individual variables. For example: x, y = (1, 2) Code language: Python (python)

Is tuple an iterator?

'tuple' object is not an iterator.

How does tuple unpacking work in Python?

When we are unpacking values into variables using tuple unpacking, the number of variables on the left side tuple must exactly match the number of values on the right side tuple . Otherwise, we'll get a ValueError .

When unpacking a tuple What happens if the number of variables on the left doesn't match the number of items in the tuple?

Because parentheses of tuples can be omitted, multiple values can be assigned to multiple variables in one line as follows. An error is raised if the number of variables does not match the number of elements.


3 Answers

The itertools crate has methods like tuples and next_tuple that can help with this.

use itertools::Itertools; // 0.9.0

fn main() {
    let v = vec![1, 2, 3];
    let (a, b) = v.iter().next_tuple().unwrap();

    assert_eq!(a, &1);
    assert_eq!(b, &2);
}
like image 147
gcp Avatar answered Oct 17 '22 12:10

gcp


This may not be exactly what you asked for, but I suppose you rarely want to convert an arbitrarily large vector to a tuple anyway. If you just want to extract the first few elements of a vector into a tuple, you can do so using slice pattern matching:

fn main() {
    let v = vec![1, 2, 3];
    let (a, b) = match &v[..] {
        &[first, second, ..] => (first, second),
        _ => unreachable!(),
    };
    assert_eq!((a, b), (1, 2));
}
like image 29
helios35 Avatar answered Oct 17 '22 12:10

helios35


I wrote this ugly recursive macro that converts a Vec to a tuple because I wanted to learn something about macros.

macro_rules! tuplet {
    { ($y:ident $(, $x:ident)*) = $v:expr } => {
        let ($y, $($x),*) = tuplet!($v ; 1 ; ($($x),*) ; ($v[0]) );
    };
    { $v:expr ; $j:expr ; ($y:ident $(, $x:ident)*) ; ($($a:expr),*) } => {
        tuplet!( $v ; $j+1 ; ($($x),*) ; ($($a),*,$v[$j]) )
    };
    { $v:expr ; $j:expr ; () ; $accu:expr } => {
        $accu
    }
}

I am new to this and probably very bad at it, so there's most likely a better way to do it. This is just a proof of concept. It allows you to write:

fn main() {
    let v = vec![1, 2, 3];
    tuplet!((a, b, c) = v);

    assert_eq!(a, 1);
    assert_eq!(b, 2);
    assert_eq!(c, 3);
}

Somewhere in that macro definition you find the part $v[$j], which you could replace by $v.nth($j) if you want to use it for iterators.

like image 5
Jesko Hüttenhain Avatar answered Oct 17 '22 10:10

Jesko Hüttenhain