1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use crate::arrays::Array;
use crate::traits::{
    meta::ArrayMeta,
    types::numeric::Numeric,
};

impl <N: Numeric> std::fmt::Display for Array<N> {

    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", build_string(self, f.precision(), f.alternate()))
    }
}

fn build_string<N: Numeric>(arr: &Array<N>, precision: Option<usize>, alternate: bool) -> String {
    if arr.is_empty().unwrap_or(true) {
        "[]".to_string()
    } else if arr.len().unwrap_or(0) == 1 {
        format!("[{}]", arr.get_elements().unwrap()[0])
    } else {
        let mut shape = arr.get_shape().unwrap();
        shape.reverse();
        let multiply = shape.iter().enumerate()
            .map(|(idx, _)| shape[0..=idx].iter().product())
            .collect::<Vec<usize>>();
        let mut str = vec!["[".repeat(multiply.len())];
        arr.get_elements().unwrap().iter().enumerate().for_each(|(idx, &elem)|
            str.push(print_subarray(&shape, idx, elem, multiply.clone(), precision, alternate))
        );
        multiply.iter().for_each(|_| str.push("]".to_string()));
        str.join("")
    }
}

fn print_subarray<N: Numeric>(shape: &[usize], idx: usize, elem: N, m: Vec<usize>, p: Option<usize>, a: bool) -> String {
    let mut str = vec![];
    if idx == 0 && shape[shape.len() - 1] != 1 {
        str.push(format_with_precision(elem, ", ", p));
    } else if idx == 0 {
        str.push(format_with_precision(elem, "", p));
    } else {
        let separators = m.iter()
            .filter(|&s| idx % s == 0)
            .count();
        str.push("]".repeat(separators));
        if separators > 0 {
            str.push(", ".to_string());
            if a {
                str.push("\n".to_string());
                str.push(" ".repeat(shape.len() - separators));
            }
        }
        str.push("[".repeat(separators));
        str.push(format_with_coma(elem, idx % shape[0] != shape[0] - 1, p));
    }
    str.join("")
}

fn format_with_coma<N: Numeric>(elem: N, condition: bool, precision: Option<usize>) -> String {
    if condition {
        format_with_precision(elem, ", ", precision)
    } else {
        format_with_precision(elem, "", precision)
    }
}

fn format_with_precision<N: Numeric>(elem: N, suffix: &str, precision: Option<usize>) -> String {
    if precision.is_some() {
        format!("{elem:.p$}{s}", elem = elem, p = precision.unwrap(), s = suffix)
    } else {
        format!("{elem}{suffix}")
    }
}