Olgierd Kowalewski
Olgierd Kowalewski

Reputation: 5

rust how recreate function from js

function add(...args){
  if (args.length === 0) return [];
  const a = args[0];
  let res = [];
  for (let i = 0; i < a.length; i++){
    const elements = args.map(x => x[i]);
    res.push(Array.isArray(a[i]) ? add(...elements) : elements.reduce((a, b) => a + b));
  }
  return res;
}
console.log(add([[1]], [[2]])); // [[3]]
console.log(add([1], [2])); // [3]

console.log(add([1, 2], [3, 4])); // [4, 6]
console.log(add([[1, 2]], [[3, 4]])); // [[4, 6]]

i want to create function which adds any amount of arrays with any depth.

i have 2 arrays

let myArray: Vec<...> = vec![...]; // and
let myArrayChanges: Vec<...> = vec![...];

how sum them with this function in rust if myArray can have diffrent depth depending on situation

Expectations: i expect working rust function

Upvotes: -4

Views: 60

Answers (1)

kmdreko
kmdreko

Reputation: 60497

In the end, your function is recursively "adding" values together, where adding arrays creates a new array based on element-wise "adding".

So all we need to know is how to "add" numbers and how to "add" arrays in such a fashion. For handling types generically we need traits; there is already a standard Add trait so lets call ours Combine:

trait Combine {
    fn combine(self, other: Self) -> Self;
}

impl Combine for i32 {
    fn combine(self, other: i32) -> i32 {
        self + other
    }
}

impl<T> Combine for Vec<T> where T: Combine {
    fn combine(self, other: Vec<T>) -> Vec<T> {
        self.into_iter().zip(other).map(|(s, o)| s.combine(o)).collect()
    }
}

And that's really it, the Vec implementation already knows how to handle itself recursively (such that Vec<Vec<i32>> automatically works as well).

fn add<T: Combine>(a: T, b: T) -> T {
    a.combine(b)
}

fn main() {
    let a = vec![1i32, 2, 3, 4];
    let b = vec![5i32, 6, 7, 8];
    
    println!("{:?}", add(a, b));
    
    let a = vec![vec![1i32, 2], vec![3, 4]];
    let b = vec![vec![5i32, 6], vec![7, 8]];
    
    println!("{:?}", add(a, b));
}
[6, 8, 10, 12]
[[6, 8], [10, 12]]

NOTES:

  • It would be nice if Combine automatically worked from the pre-existing Add (assuming that is your intention) but unfortunately that means a "conflict" with Add for Vec - which doesn't exist but the compiler doesn't allow us to write code assuming it doesn't. So you will need to define Combine for all the types you're going to want to "add" yourself (macros can help if you need a lot).
  • You've written add(...args) such that it can be passed an arbitrary number of arguments, but that isn't a thing in Rust. If you want that then you could make a macro to iteratively build .combine(...) or it'd be better to just make a function that takes an iterator of values to combine - an easy .reduce away.

Upvotes: 1

Related Questions