How to simplify this?

I have this function:

pub fn two_sum(numbers: Vec<i32>, target: i32) -> Vec<i32> {
      let mut iter = numbers.iter().enumerate();
      
      if let Some((i, l)) = iter.next() {
          if let Some((j, r)) = iter.by_ref().rev().next() {
              if l + r == target {
                  vec![i as i32 + 1, j as i32 + 1]
              } else {
                  std::iter::repeat(()).try_fold((l + r > target, (i, l), (j, r)), move |(cond, (i, l), (j, r)), ()| {
                      if cond {
                          if let Some((j, r)) = iter.by_ref().rev().next() {
                              if l + r == target {
                                  Err(vec![i as i32 + 1, j as i32 + 1])
                              } else {
                                  Ok((l + r > target, (i, l), (j, r)))
                              }
                          } else {
                              Err(vec![])
                          }
                      } else {
                          if let Some((i, l)) = iter.next() {
                              if l + r == target {
                                  Err(vec![i as i32 + 1, j as i32 + 1])
                              } else {                                    
                                  Ok((l + r > target, (i, l), (j, r)))
                              }
                          } else {
                              Err(vec![])
                          }
                      }
                  }).err().unwrap_or(vec![])
              }
          } else {
              vec![]
          }
      } else {
          vec![]
      }
 }

Using for loops it can be simplified but, I want to be solved it ONLY using iterators. How to simplify only using iterators?

That's quite a complicated function. What does it do?

It solves this leetcode twosum problem.

I don't think there is any elegant solution using only iterators. I would use a while loop.

What I understood in iterators is it is really really hard to arbitrarily change direction while in the middle of iteration which can be seen in the above function. Is there any neat way to do this?

Here's what I would consider an elegant solution:

pub fn two_sum(numbers: Vec<i32>, target: i32) -> Vec<i32> {
    let len = numbers.len() as i32;
    let mut i = 0;
    let mut j = len-1;
    
    while i < len && j >= 0 {
        let current = numbers[i as usize] + numbers[j as usize];
        
        if current < target {
            i += 1;
        } else if current > target {
            j -= 1;
        } else {
            return vec![1+i, 1+j];
        }
    }
    
    vec![]
}

There are no elegant solutions that involve iterators.

5 Likes

Here is a version using iterators:

use std::cmp::Ordering;

pub fn two_sum(numbers: Vec<i32>, target: i32) -> Vec<i32> {
    let mut iter = numbers.iter().enumerate();
    let mut front = iter.next();
    let mut back = iter.next_back();
    while let (Some((a_idx, a)), Some((b_idx, b))) = (front, back) {
        match (a + b).cmp(&target) {
            Ordering::Less => front = iter.next(),
            Ordering::Greater => back = iter.next_back(),
            Ordering::Equal => return vec![(a_idx as i32) + 1, (b_idx as i32) + 1],
        }
    }
    panic!("no solution")
}
7 Likes

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.