///
/// This example parses, sorts and groups the iris dataset
/// and does some simple manipulations.
///
/// Iterators and itertools functionality are used throughout.
use itertools::Itertools;
use std::collections::HashMap;
use std::iter::repeat;
use std::num::ParseFloatError;
use std::str::FromStr;
static DATA: &
'static str = include_str!("iris.data");
#[derive(Clone, Debug)]
struct Iris {
name: String,
data: [f32;
4],
}
#[derive(Clone, Debug)]
enum ParseError {
Numeric(ParseFloatError),
Other(&
'static str),
}
impl From<ParseFloatError>
for ParseError {
fn from(err: ParseFloatError) ->
Self {
ParseError::Numeric(err)
}
}
/// Parse an Iris from a comma-separated line
impl FromStr
for Iris {
type Err = ParseError;
fn from_str(s: &str) -> Result<
Self,
Self::Err> {
let mut iris = Iris { name:
"".into(), data: [
0.;
4] };
let mut parts = s.split(
",").map(str::trim);
// using Iterator::by_ref()
for (index, part)
in parts.by_ref().take(
4).enumerate() {
iris.data[index] = part.parse::<f32>()?;
}
if let Some(name) = parts.next() {
iris.name = name.into();
}
else {
return Err(ParseError::Other(
"Missing name"))
}
Ok(iris)
}
}
fn main() {
// using Itertools::fold_results to create the result of parsing
let irises = DATA.lines()
.map(str::parse)
.fold_ok(Vec::new(), |
mut v, iris: Iris| {
v.push(iris);
v
});
let mut irises =
match irises {
Err(e) => {
println!(
"Error parsing: {:?}", e);
std::process::exit(
1);
}
Ok(data) => data,
};
// Sort them and group them
irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name));
// using Iterator::cycle()
let mut plot_symbols =
"+ox".chars().cycle();
let mut symbolmap = HashMap::new();
// using Itertools::group_by
for (species, species_group)
in &irises.iter().group_by(|iris| &iris.name) {
// assign a plot symbol
symbolmap.entry(species).or_insert_with(|| {
plot_symbols.next().unwrap()
});
println!(
"{} (symbol={})", species, symbolmap[species]);
for iris
in species_group {
// using Itertools::format for lazy formatting
println!(
"{:>3.1}", iris.data.iter().format(
", "));
}
}
// Look at all combinations of the four columns
//
// See https://en.wikipedia.org/wiki/Iris_flower_data_set
//
let n =
30;
// plot size
let mut plot = vec![
' '; n * n];
// using Itertools::tuple_combinations
for (a, b)
in (
0..
4).tuple_combinations() {
println!(
"Column {} vs {}:", a, b);
// Clear plot
//
// using std::iter::repeat;
// using Itertools::set_from
plot.iter_mut().set_from(repeat(
' '));
// using Itertools::minmax
let min_max = |data: &[Iris], col| {
data.iter()
.map(|iris| iris.data[col])
.minmax()
.into_option()
.expect(
"Can't find min/max of empty iterator")
};
let (min_x, max_x) = min_max(&irises, a);
let (min_y, max_y) = min_max(&irises, b);
// Plot the data points
let round_to_grid = |x, min, max| ((x - min) / (max - min) * ((n -
1)
as f32))
as usize;
let flip = |ix| n -
1 - ix;
// reverse axis direction
for iris
in &irises {
let ix = round_to_grid(iris.data[a], min_x, max_x);
let iy = flip(round_to_grid(iris.data[b], min_y, max_y));
plot[n * iy + ix] = symbolmap[&iris.name];
}
// render plot
//
// using Itertools::join
for line
in plot.chunks(n) {
println!(
"{}", line.iter().join(
" "))
}
}
}