What's the ideomatic way to chain an iterator or reversed iterator?

I have a line of vertice, and want to try coupling it with another line of vertice.

Line 1: [1, 10, 20, 5]
Line 2: [1, 2, 3]

expected output:
Line 3: [3, 2, 1, 10, 20, 5] (or reversed order, doesn't matter)

In the code I have to check 4 ways the lines can match. For example, lines with vertice [1, 2] and [2, 3] can appear like these:

[1, 2], [2, 3]
[1, 2], [3, 2] # need to reverse left or right
[2, 1], [2, 3] # need to reverse left or right
[2, 1], [3, 2]

The output should be [1, 2, 3] or [3, 2, 1].

Here's the code I could finally wrote. (In the real app, Line has other attributes, but for simplicity I omit them here.)

#[derive(Clone)]
struct Line {
	vertice: Vec<i64>
}

impl Line {
	fn ends(&self) -> [i64; 2] {
		[self.vertice[0].clone(), self.vertice[self.vertice.len() - 1].clone()]
	}
	fn couple(&self, other: &Line) -> Option<Line> {
		let new_vertice:Vec<i64> = {
			let se = self.ends();
			let oe = other.ends();
			let mine = &self.vertice;
			let their = &other.vertice;

			if se[0] == oe[0] {
				mine[1..].iter().rev().into_iter().chain(their.iter()).cloned().collect()
			} else if se[0] == oe[1] {
				their.iter().chain(mine[1..].iter()).cloned().collect()
			} else if se[1] == oe[0] {
				mine.iter().chain(their[1..].iter()).cloned().collect()
			} else if se[1] == oe[1] {
				mine[..mine.len() - 1].iter().chain(their.iter().rev()).cloned().collect()
			} else {
				return None;
			}
		};

		Some(Line { vertice: new_vertice })
	}
}

I tried abstracting the code to reduce the repetitions of chain/cloned/collect calls, but it turned out even worse. A function can't accept Iterator/Rev<X>, only one of this kind, and I couldn't wrap them together. If instead I make a function accepting Vec, I need to call iter/cloned/collect to make a Vec before it.


fn couple2(a: &Vec<i64>, b: &Vec<i64>) -> Vec<i64> {
	a.iter().chain(b.iter()).cloned().collect()
}

...

			if se[0] == oe[0] {
				couple2(&mine[1..].iter().rev().cloned().collect(), their)
			} else if se[0] == oe[1] {
				couple2(their, &mine[1..].iter().cloned().collect())
			} else if se[1] == oe[0] {
				couple2(mine, &their[1..].iter().cloned().collect())
			} else if se[1] == oe[1] {
				couple2(&mine[..mine.len() - 1].iter().cloned().collect(), &their.iter().rev().cloned().collect())
...

Did I miss some more ideomatic way to do this?

Maybe

fn couple2<'a, 'b>(
    a: impl IntoIterator<Item = &'a i64>,
    b: impl IntoIterator<Item = &'b i64>,
) -> Vec<i64> {
    a.into_iter()
        .copied()
        .chain(b.into_iter().copied())
        .collect()
}

....

            if se[0] == oe[0] {
                couple2(mine[1..].iter().rev(), their)
            } else if se[0] == oe[1] {
                couple2(their, &mine[1..])
            } else if se[1] == oe[0] {
                couple2(mine, &their[1..])
            } else if se[1] == oe[1] {
                couple2(&mine[..mine.len() - 1], their.iter().rev())
1 Like

You could also integrate the logic of skipping one element of the second part into couple2:

fn couple2<'a, 'b>(
    a: impl IntoIterator<Item = &'a i64>,
    b: impl IntoIterator<Item = &'b i64>,
) -> Vec<i64> {
    a.into_iter()
        .copied()
        .chain(b.into_iter().copied().skip(1))
        .collect()
}

....

            if se[0] == oe[0] {
                couple2(mine.iter().rev(), their)
            } else if se[0] == oe[1] {
                couple2(their, mine)
            } else if se[1] == oe[0] {
                couple2(mine, their)
            } else if se[1] == oe[1] {
                couple2(mine, their.iter().rev())

(untested)

1 Like

Another option:

fn couple2(a: impl Iterator<Item = i64>, b: impl Iterator<Item = i64>) -> Vec<i64> {
    a.chain(b.skip(1)).collect()
}
....
            let mine = self.vertice.iter().copied();
            let their = other.vertice.iter().copied();

            if se[0] == oe[0] {
                couple2(mine.rev(), their)
            } else if se[0] == oe[1] {
                couple2(their, mine)
            } else if se[1] == oe[0] {
                couple2(mine, their)
            } else if se[1] == oe[1] {
                couple2(mine, their.rev())
            } else {
                return None;
            }
1 Like

Wow, it compiles!

I can't restore those old versions I had in the editor, but this looks a lot simpler and cleaner. What I missed was skip(1).

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.