Task

Display a finite linear combination in an infinite vector basis 



(

e

1


,

e

2


,
…
)


{\displaystyle (e_{1},e_{2},\ldots )}

.

Write a function that, when given a finite list of scalars 



(

α

1


,

α

2


,
…
)


{\displaystyle (\alpha ^{1},\alpha ^{2},\ldots )}

, 
creates a string representing the linear combination 




∑

i



α

i



e

i




{\displaystyle \sum _{i}\alpha ^{i}e_{i}}

 in an explicit format often used in mathematics, that is:






α


i

1





e


i

1




±

|


α


i

2





|


e


i

2




±

|


α


i

3





|


e


i

3




±
…


{\displaystyle \alpha ^{i_{1}}e_{i_{1}}\pm |\alpha ^{i_{2}}|e_{i_{2}}\pm |\alpha ^{i_{3}}|e_{i_{3}}\pm \ldots }


where 




α


i

k




≠
0


{\displaystyle \alpha ^{i_{k}}\neq 0}







The output must comply to the following rules:

   don't show null terms, unless the whole combination is null. 
 e(1)     is fine,     e(1) + 0*e(3)     or     e(1) + 0     is wrong.
   don't show scalars when they are equal to one or minus one. 
 e(3)     is fine,     1*e(3)     is wrong.
   don't prefix by a minus sign if it follows a preceding term.   Instead you use subtraction. 
 e(4) - e(5)     is fine,     e(4) + -e(5)     is wrong.


Show here output for the following lists of scalars:

 1)    1,  2,  3
 2)    0,  1,  2,  3
 3)    1,  0,  3,  4
 4)    1,  2,  0
 5)    0,  0,  0
 6)    0
 7)    1,  1,  1
 8)   -1, -1, -1
 9)   -1, -2,  0, -3
10)   -1



 
use std::fmt::{Display, Formatter, Result};
use std::process::exit;
 
struct Coefficient(usize, f64);
 
impl Display for Coefficient {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let i = self.0;
        let c = self.1;
 
        if c == 0. {
            return Ok(());
        }
 
        write!(
            f,
            " {} {}e({})",
            if c < 0. {
                "-"
            } else if f.alternate() {
                " "
            } else {
                "+"
            },
            if (c.abs() - 1.).abs() < f64::EPSILON {
                "".to_string()
            } else {
                c.abs().to_string() + "*"
            },
            i + 1
        )
    }
}
 
fn usage() {
    println!("Usage: display-linear-combination a1 [a2 a3 ...]");
}
 
fn linear_combination(coefficients: &[f64]) -> String {
    let mut string = String::new();
 
    let mut iter = coefficients.iter().enumerate();
 
    // find first nonzero argument
    loop {
        match iter.next() {
            Some((_, &c)) if c == 0. => {
                continue;
            }
            Some((i, &c)) => {
                string.push_str(format!("{:#}", Coefficient(i, c)).as_str());
                break;
            }
            None => {
                string.push('0');
                return string;
            }
        }
    }
 
    // print subsequent arguments
    for (i, &c) in iter {
        string.push_str(format!("{}", Coefficient(i, c)).as_str());
    }
 
    string
}
 
fn main() {
    let mut coefficients = Vec::new();
    let mut args = std::env::args();
 
    args.next(); // drop first argument
 
    // parse arguments into floats
    for arg in args {
        let c = arg.parse::<f64>().unwrap_or_else(|e| {
            eprintln!("Failed to parse argument \"{}\": {}", arg, e);
            exit(-1);
        });
        coefficients.push(c);
    }
 
    // no arguments, print usage and exit
    if coefficients.is_empty() {
        usage();
        return;
    }
 
    println!("{}", linear_combination(&coefficients));
}
 