Repository: vks/average (language: rust)

Issue:
Implement `std::iter::FromIterator<&f64>`
I might be missing something obvious as I'm new to Rust, but why not implement `from_iter` for `&f64`?  Usually I'll have an iterator of references, so I must manually copy the values:
```
    let a:Vec<f64> = vec![1.0, 2.0, 12.0];
    let k:Kurtosis = a.iter().map(|x| *x).collect();
    println!("{:?}", k.kurtosis());
```
otherwise I'll get the error:
```
error[E0277]: the trait bound `average::Kurtosis: std::iter::FromIterator<&f64>` is not satisfied
  --> src/main.rs:24:31
   |
24 |     let k:Kurtosis = a.iter().collect();
   |                               ^^^^^^^ a collection of type `average::Kurtosis` cannot be built from an iterator over elements of type `&f64`
   |
   = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `average::Kurtosis`
```
Implement `std::iter::FromIterator<&f64>`
I might be missing something obvious as I'm new to Rust, but why not implement `from_iter` for `&f64`?  Usually I'll have an iterator of references, so I must manually copy the values:
```
    let a:Vec<f64> = vec![1.0, 2.0, 12.0];
    let k:Kurtosis = a.iter().map(|x| *x).collect();
    println!("{:?}", k.kurtosis());
```
otherwise I'll get the error:
```
error[E0277]: the trait bound `average::Kurtosis: std::iter::FromIterator<&f64>` is not satisfied
  --> src/main.rs:24:31
   |
24 |     let k:Kurtosis = a.iter().collect();
   |                               ^^^^^^^ a collection of type `average::Kurtosis` cannot be built from an iterator over elements of type `&f64`
   |
   = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `average::Kurtosis`
```


Discussion / hints:
Yes, this is a known papercut. I decided to do it this way, because it is not so clear how it should be done for the weighted statistics, which take `(f64, f64)` iterators. Should they support `&(f64, f64)`, `(&f64, f64)` etc.?  There might be some implications on type inference as well.

Another option is to implement `FromIterator<T>` for `T: Into<f64>`, but that is probably a bad idea.

Looking at the standard library:
```rust
impl<'a> FromIterator<&'a char> for String { ... }
impl FromIterator<char> for String { ... }
```
So I probably will implement `FromIterator<&f64>` and `FromIterator<&(f64, f64)>`.
This breaks the following code:
```rust
let a: Min = (1..6).map(Into::into).collect();
```
However, it can be fixed by being more explicit (which is probably better anyway):
```rust
let a: Min = (1..6).map(f64::from).collect();
```
Yes, this is a known papercut. I decided to do it this way, because it is not so clear how it should be done for the weighted statistics, which take `(f64, f64)` iterators. Should they support `&(f64, f64)`, `(&f64, f64)` etc.?  There might be some implications on type inference as well.

Another option is to implement `FromIterator<T>` for `T: Into<f64>`, but that is probably a bad idea.

Looking at the standard library:
```rust
impl<'a> FromIterator<&'a char> for String { ... }
impl FromIterator<char> for String { ... }
```
So I probably will implement `FromIterator<&f64>` and `FromIterator<&(f64, f64)>`.
This breaks the following code:
```rust
let a: Min = (1..6).map(Into::into).collect();
```
However, it can be fixed by being more explicit (which is probably better anyway):
```rust
let a: Min = (1..6).map(f64::from).collect();
```

Fix patch:
diff --git a/src/lib.rs b/src/lib.rs
index a857c05..df56908 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -29,7 +29,7 @@
 //! ```
 //! use average::{MeanWithError, Estimate};
 //!
-//! let mut a: MeanWithError = (1..6).map(Into::into).collect();
+//! let mut a: MeanWithError = (1..6).map(f64::from).collect();
 //! a.add(42.);
 //! println!("The mean is {} ± {}.", a.mean(), a.error());
 //! ```
diff --git a/src/macros.rs b/src/macros.rs
index c4a09ff..4e1583d 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -44,7 +44,7 @@ macro_rules! assert_almost_eq {
 ///
 /// concatenate!(MinMax, [Min, min], [Max, max]);
 ///
-/// let s: MinMax = (1..6).map(Into::into).collect();
+/// let s: MinMax = (1..6).map(f64::from).collect();
 ///
 /// assert_eq!(s.min(), 1.0);
 /// assert_eq!(s.max(), 5.0);
@@ -157,5 +157,17 @@ macro_rules! impl_from_iterator {
                 e
             }
         }
+
+        impl<'a> ::core::iter::FromIterator<&'a f64> for $name {
+            fn from_iter<T>(iter: T) -> $name
+                where T: IntoIterator<Item=&'a f64>
+            {
+                let mut e = $name::new();
+                for &i in iter {
+                    e.add(i);
+                }
+                e
+            }
+        }
     };
 }
diff --git a/src/minmax.rs b/src/minmax.rs
index 31b85b3..2f30ec1 100644
--- a/src/minmax.rs
+++ b/src/minmax.rs
@@ -20,7 +20,7 @@ fn max(a: f64, b: f64) -> f64 {
 /// ```
 /// use average::Min;
 ///
-/// let a: Min = (1..6).map(Into::into).collect();
+/// let a: Min = (1..6).map(f64::from).collect();
 /// println!("The minimum is {}.", a.min());
 /// ```
 #[derive(Debug, Clone)]
@@ -82,9 +82,9 @@ impl Merge for Min {
     ///
     /// let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.];
     /// let (left, right) = sequence.split_at(3);
-    /// let min_total: Min = sequence.iter().map(|x| *x).collect();
-    /// let mut min_left: Min = left.iter().map(|x| *x).collect();
-    /// let min_right: Min = right.iter().map(|x| *x).collect();
+    /// let min_total: Min = sequence.iter().collect();
+    /// let mut min_left: Min = left.iter().collect();
+    /// let min_right: Min = right.iter().collect();
     /// min_left.merge(&min_right);
     /// assert_eq!(min_total.min(), min_left.min());
     /// ```
@@ -102,7 +102,7 @@ impl Merge for Min {
 /// ```
 /// use average::Max;
 ///
-/// let a: Max = (1..6).map(Into::into).collect();
+/// let a: Max = (1..6).map(f64::from).collect();
 /// assert_eq!(a.max(), 5.);
 /// ```
 #[derive(Debug, Clone)]
@@ -164,9 +164,9 @@ impl Merge for Max {
     ///
     /// let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.];
     /// let (left, right) = sequence.split_at(3);
-    /// let max_total: Max = sequence.iter().map(|x| *x).collect();
-    /// let mut max_left: Max = left.iter().map(|x| *x).collect();
-    /// let max_right: Max = right.iter().map(|x| *x).collect();
+    /// let max_total: Max = sequence.iter().collect();
+    /// let mut max_left: Max = left.iter().collect();
+    /// let max_right: Max = right.iter().collect();
     /// max_left.merge(&max_right);
     /// assert_eq!(max_total.max(), max_left.max());
     /// ```
diff --git a/src/moments/mean.rs b/src/moments/mean.rs
index d5cd465..70ec5e3 100644
--- a/src/moments/mean.rs
+++ b/src/moments/mean.rs
@@ -6,7 +6,7 @@
 /// ```
 /// use average::Mean;
 ///
-/// let a: Mean = (1..6).map(Into::into).collect();
+/// let a: Mean = (1..6).map(f64::from).collect();
 /// println!("The mean is {}.", a.mean());
 /// ```
 #[derive(Debug, Clone)]
@@ -100,9 +100,9 @@ impl Merge for Mean {
     ///
     /// let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.];
     /// let (left, right) = sequence.split_at(3);
-    /// let avg_total: Mean = sequence.iter().map(|x| *x).collect();
-    /// let mut avg_left: Mean = left.iter().map(|x| *x).collect();
-    /// let avg_right: Mean = right.iter().map(|x| *x).collect();
+    /// let avg_total: Mean = sequence.iter().collect();
+    /// let mut avg_left: Mean = left.iter().collect();
+    /// let avg_right: Mean = right.iter().collect();
     /// avg_left.merge(&avg_right);
     /// assert_eq!(avg_total.mean(), avg_left.mean());
     /// ```
diff --git a/src/moments/variance.rs b/src/moments/variance.rs
index 9de9c64..29ee966 100644
--- a/src/moments/variance.rs
+++ b/src/moments/variance.rs
@@ -9,7 +9,7 @@
 /// ```
 /// use average::Variance;
 ///
-/// let a: Variance = (1..6).map(Into::into).collect();
+/// let a: Variance = (1..6).map(f64::from).collect();
 /// println!("The mean is {} ± {}.", a.mean(), a.error());
 /// ```
 #[derive(Debug, Clone)]
@@ -139,9 +139,9 @@ impl Merge for Variance {
     ///
     /// let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.];
     /// let (left, right) = sequence.split_at(3);
-    /// let avg_total: Variance = sequence.iter().map(|x| *x).collect();
-    /// let mut avg_left: Variance = left.iter().map(|x| *x).collect();
-    /// let avg_right: Variance = right.iter().map(|x| *x).collect();
+    /// let avg_total: Variance = sequence.iter().collect();
+    /// let mut avg_left: Variance = left.iter().collect();
+    /// let avg_right: Variance = right.iter().collect();
     /// avg_left.merge(&avg_right);
     /// assert_eq!(avg_total.mean(), avg_left.mean());
     /// assert_eq!(avg_total.sample_variance(), avg_left.sample_variance());
diff --git a/src/weighted_mean.rs b/src/weighted_mean.rs
index ea9d8a1..1aa56c5 100644
--- a/src/weighted_mean.rs
+++ b/src/weighted_mean.rs
@@ -91,6 +91,18 @@ impl core::iter::FromIterator<(f64, f64)> for WeightedMean {
     }
 }
 
+impl<'a> core::iter::FromIterator<&'a (f64, f64)> for WeightedMean {
+    fn from_iter<T>(iter: T) -> WeightedMean
+        where T: IntoIterator<Item=&'a (f64, f64)>
+    {
+        let mut a = WeightedMean::new();
+        for &(i, w) in iter {
+            a.add(i, w);
+        }
+        a
+    }
+}
+
 impl Merge for WeightedMean {
     /// Merge another sample into this one.
     ///
@@ -104,9 +116,9 @@ impl Merge for WeightedMean {
     ///     (1., 0.1), (2., 0.2), (3., 0.3), (4., 0.4), (5., 0.5),
     ///     (6., 0.6), (7., 0.7), (8., 0.8), (9., 0.9)];
     /// let (left, right) = weighted_sequence.split_at(3);
-    /// let avg_total: WeightedMean = weighted_sequence.iter().map(|&x| x).collect();
-    /// let mut avg_left: WeightedMean = left.iter().map(|&x| x).collect();
-    /// let avg_right: WeightedMean = right.iter().map(|&x| x).collect();
+    /// let avg_total: WeightedMean = weighted_sequence.iter().collect();
+    /// let mut avg_left: WeightedMean = left.iter().collect();
+    /// let avg_right: WeightedMean = right.iter().collect();
     /// avg_left.merge(&avg_right);
     /// assert!((avg_total.mean() - avg_left.mean()).abs() < 1e-15);
     /// ```
@@ -276,9 +288,9 @@ impl Merge for WeightedMeanWithError {
     ///     (1., 0.1), (2., 0.2), (3., 0.3), (4., 0.4), (5., 0.5),
     ///     (6., 0.6), (7., 0.7), (8., 0.8), (9., 0.9)];
     /// let (left, right) = weighted_sequence.split_at(3);
-    /// let avg_total: WeightedMeanWithError = weighted_sequence.iter().map(|&x| x).collect();
-    /// let mut avg_left: WeightedMeanWithError = left.iter().map(|&x| x).collect();
-    /// let avg_right: WeightedMeanWithError = right.iter().map(|&x| x).collect();
+    /// let avg_total: WeightedMeanWithError = weighted_sequence.iter().collect();
+    /// let mut avg_left: WeightedMeanWithError = left.iter().collect();
+    /// let avg_right: WeightedMeanWithError = right.iter().collect();
     /// avg_left.merge(&avg_right);
     /// assert!((avg_total.weighted_mean() - avg_left.weighted_mean()).abs() < 1e-15);
     /// assert!((avg_total.error() - avg_left.error()).abs() < 1e-15);
@@ -308,3 +320,15 @@ impl core::iter::FromIterator<(f64, f64)> for WeightedMeanWithError {
         a
     }
 }
+
+impl<'a> core::iter::FromIterator<&'a (f64, f64)> for WeightedMeanWithError {
+    fn from_iter<T>(iter: T) -> WeightedMeanWithError
+        where T: IntoIterator<Item=&'a (f64, f64)>
+    {
+        let mut a = WeightedMeanWithError::new();
+        for &(i, w) in iter {
+            a.add(i, w);
+        }
+        a
+    }
+}


Test patch:
diff --git a/tests/kurtosis.rs b/tests/kurtosis.rs
index 833348d..8b6c707 100644
--- a/tests/kurtosis.rs
+++ b/tests/kurtosis.rs
@@ -65,9 +65,9 @@ fn merge() {
     let sequence: &[f64] = &[1., 2., 3., -4., 5.1, 6.3, 7.3, -8., 9., 1.];
     for mid in 0..sequence.len() {
         let (left, right) = sequence.split_at(mid);
-        let avg_total: Kurtosis = sequence.iter().map(|x| *x).collect();
-        let mut avg_left: Kurtosis = left.iter().map(|x| *x).collect();
-        let avg_right: Kurtosis = right.iter().map(|x| *x).collect();
+        let avg_total: Kurtosis = sequence.iter().collect();
+        let mut avg_left: Kurtosis = left.iter().collect();
+        let avg_right: Kurtosis = right.iter().collect();
         avg_left.merge(&avg_right);
         assert_eq!(avg_total.len(), avg_left.len());
         assert_almost_eq!(avg_total.mean(), avg_left.mean(), 1e-14);
diff --git a/tests/macros.rs b/tests/macros.rs
index a3a09ba..9d3f7eb 100644
--- a/tests/macros.rs
+++ b/tests/macros.rs
@@ -33,7 +33,7 @@ fn concatenate_simple() {
     }
 
     {
-        let s: MinMax = (1..6).map(Into::into).collect();
+        let s: MinMax = (1..6).map(f64::from).collect();
 
         assert_eq!(s.min(), 1.0);
         assert_eq!(s.max(), 5.0);
@@ -48,7 +48,7 @@ fn concatenate_moments() {
         [Variance, variance, mean, sample_variance],
         [Quantile, quantile, quantile]);
 
-    let e: Estimator = (1..6).map(Into::into).collect();
+    let e: Estimator = (1..6).map(f64::from).collect();
 
     assert_eq!(e.mean(), 3.0);
     assert_eq!(e.sample_variance(), 2.5);
diff --git a/tests/max.rs b/tests/max.rs
index ca2711e..7f14811 100644
--- a/tests/max.rs
+++ b/tests/max.rs
@@ -40,11 +40,11 @@ fn merge() {
     let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.];
     for mid in 1..sequence.len() {
         let (left, right) = sequence.split_at(mid);
-        let max_total: Max = sequence.iter().map(|x| *x).collect();
+        let max_total: Max = sequence.iter().collect();
         assert_eq!(max_total.max(), 9.);
-        let mut max_left: Max = left.iter().map(|x| *x).collect();
+        let mut max_left: Max = left.iter().collect();
         assert_eq!(max_left.max(), sequence[mid - 1]);
-        let max_right: Max = right.iter().map(|x| *x).collect();
+        let max_right: Max = right.iter().collect();
         assert_eq!(max_right.max(), 9.);
         max_left.merge(&max_right);
         assert_eq!(max_total.max(), max_left.max());
diff --git a/tests/mean.rs b/tests/mean.rs
index 43b761c..156d2b6 100644
--- a/tests/mean.rs
+++ b/tests/mean.rs
@@ -55,7 +55,7 @@ fn numerically_unstable() {
     // The naive algorithm fails for this example due to cancelation.
     let big = 1e9;
     let sample = &[big + 4., big + 7., big + 13., big + 16.];
-    let a: MeanWithError = sample.iter().map(|x| *x).collect();
+    let a: MeanWithError = sample.iter().collect();
     assert_eq!(a.sample_variance(), 30.);
 }
 
@@ -64,9 +64,9 @@ fn merge() {
     let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.];
     for mid in 0..sequence.len() {
         let (left, right) = sequence.split_at(mid);
-        let avg_total: MeanWithError = sequence.iter().map(|x| *x).collect();
-        let mut avg_left: MeanWithError = left.iter().map(|x| *x).collect();
-        let avg_right: MeanWithError = right.iter().map(|x| *x).collect();
+        let avg_total: MeanWithError = sequence.iter().collect();
+        let mut avg_left: MeanWithError = left.iter().collect();
+        let avg_right: MeanWithError = right.iter().collect();
         avg_left.merge(&avg_right);
         assert_eq!(avg_total.len(), avg_left.len());
         assert_eq!(avg_total.mean(), avg_left.mean());
diff --git a/tests/min.rs b/tests/min.rs
index b99ca99..b50173d 100644
--- a/tests/min.rs
+++ b/tests/min.rs
@@ -40,11 +40,11 @@ fn merge() {
     let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.];
     for mid in 1..sequence.len() {
         let (left, right) = sequence.split_at(mid);
-        let min_total: Min = sequence.iter().map(|x| *x).collect();
+        let min_total: Min = sequence.iter().collect();
         assert_eq!(min_total.min(), 1.);
-        let mut min_left: Min = left.iter().map(|x| *x).collect();
+        let mut min_left: Min = left.iter().collect();
         assert_eq!(min_left.min(), 1.);
-        let min_right: Min = right.iter().map(|x| *x).collect();
+        let min_right: Min = right.iter().collect();
         assert_eq!(min_right.min(), sequence[mid]);
         min_left.merge(&min_right);
         assert_eq!(min_total.min(), min_left.min());
diff --git a/tests/moments.rs b/tests/moments.rs
index 08d302d..4e0ae54 100644
--- a/tests/moments.rs
+++ b/tests/moments.rs
@@ -81,9 +81,9 @@ fn merge() {
     let sequence: &[f64] = &[1., 2., 3., -4., 5.1, 6.3, 7.3, -8., 9., 1.];
     for mid in 0..sequence.len() {
         let (left, right) = sequence.split_at(mid);
-        let avg_total: Moments = sequence.iter().map(|x| *x).collect();
-        let mut avg_left: Moments = left.iter().map(|x| *x).collect();
-        let avg_right: Moments = right.iter().map(|x| *x).collect();
+        let avg_total: Moments = sequence.iter().collect();
+        let mut avg_left: Moments = left.iter().collect();
+        let avg_right: Moments = right.iter().collect();
         avg_left.merge(&avg_right);
         assert_eq!(avg_total.len(), avg_left.len());
         assert_almost_eq!(avg_total.mean(), avg_left.mean(), 1e-14);
diff --git a/tests/skewness.rs b/tests/skewness.rs
index 4534618..9dbddfd 100644
--- a/tests/skewness.rs
+++ b/tests/skewness.rs
@@ -63,9 +63,9 @@ fn merge() {
     let sequence: &[f64] = &[1., 2., 3., -4., 5., 6., 7., 8., 9., 1.];
     for mid in 0..sequence.len() {
         let (left, right) = sequence.split_at(mid);
-        let avg_total: Skewness = sequence.iter().map(|x| *x).collect();
-        let mut avg_left: Skewness = left.iter().map(|x| *x).collect();
-        let avg_right: Skewness = right.iter().map(|x| *x).collect();
+        let avg_total: Skewness = sequence.iter().collect();
+        let mut avg_left: Skewness = left.iter().collect();
+        let avg_right: Skewness = right.iter().collect();
         avg_left.merge(&avg_right);
         assert_eq!(avg_total.len(), avg_left.len());
         assert_almost_eq!(avg_total.mean(), avg_left.mean(), 1e-14);
diff --git a/tests/streaming_stats.rs b/tests/streaming_stats.rs
index 45aeb73..f8c5bbc 100644
--- a/tests/streaming_stats.rs
+++ b/tests/streaming_stats.rs
@@ -21,7 +21,7 @@ fn initialize_vec(size: usize) -> Vec<f64> {
 #[test]
 fn average_vs_streaming_stats_small() {
     let values = initialize_vec(100);
-    let a: average::MeanWithError = values.iter().map(|x| *x).collect();
+    let a: average::MeanWithError = values.iter().collect();
     let b: stats::OnlineStats = values.iter().map(|x| *x).collect();
     assert_almost_eq!(a.mean(), b.mean(), 1e-16);
     assert_almost_eq!(a.population_variance(), b.variance(), 1e-14);
@@ -30,7 +30,7 @@ fn average_vs_streaming_stats_small() {
 #[test]
 fn average_vs_streaming_stats_large() {
     let values = initialize_vec(1_000_000);
-    let a: average::MeanWithError = values.iter().map(|x| *x).collect();
+    let a: average::MeanWithError = values.iter().collect();
     let b: stats::OnlineStats = values.iter().map(|x| *x).collect();
     assert_almost_eq!(a.mean(), b.mean(), 1e-16);
     assert_almost_eq!(a.population_variance(), b.variance(), 1e-13);
diff --git a/tests/weighted_mean.rs b/tests/weighted_mean.rs
index 114aa92..3f4816a 100644
--- a/tests/weighted_mean.rs
+++ b/tests/weighted_mean.rs
@@ -111,9 +111,9 @@ fn merge_weighted() {
         (6., 0.6), (7., 0.7), (8., 0.8), (9., 0.)];
     for mid in 0..sequence.len() {
         let (left, right) = sequence.split_at(mid);
-        let avg_total: WeightedMeanWithError = sequence.iter().map(|&(x, w)| (x, w)).collect();
-        let mut avg_left: WeightedMeanWithError = left.iter().map(|&(x, w)| (x, w)).collect();
-        let avg_right: WeightedMeanWithError = right.iter().map(|&(x, w)| (x, w)).collect();
+        let avg_total: WeightedMeanWithError = sequence.iter().collect();
+        let mut avg_left: WeightedMeanWithError = left.iter().collect();
+        let avg_right: WeightedMeanWithError = right.iter().collect();
         avg_left.merge(&avg_right);
         assert_eq!(avg_total.len(), avg_left.len());
         assert_almost_eq!(avg_total.sum_weights(), avg_left.sum_weights(), 1e-15);