iris.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. ///
  2. /// This example parses, sorts and groups the iris dataset
  3. /// and does some simple manipulations.
  4. ///
  5. /// Iterators and itertools functionality are used throughout.
  6. use itertools::Itertools;
  7. use std::collections::HashMap;
  8. use std::iter::repeat;
  9. use std::num::ParseFloatError;
  10. use std::str::FromStr;
  11. static DATA: &'static str = include_str!("iris.data");
  12. #[derive(Clone, Debug)]
  13. struct Iris {
  14. name: String,
  15. data: [f32; 4],
  16. }
  17. #[derive(Clone, Debug)]
  18. enum ParseError {
  19. Numeric(ParseFloatError),
  20. Other(&'static str),
  21. }
  22. impl From<ParseFloatError> for ParseError {
  23. fn from(err: ParseFloatError) -> Self {
  24. ParseError::Numeric(err)
  25. }
  26. }
  27. /// Parse an Iris from a comma-separated line
  28. impl FromStr for Iris {
  29. type Err = ParseError;
  30. fn from_str(s: &str) -> Result<Self, Self::Err> {
  31. let mut iris = Iris { name: "".into(), data: [0.; 4] };
  32. let mut parts = s.split(",").map(str::trim);
  33. // using Iterator::by_ref()
  34. for (index, part) in parts.by_ref().take(4).enumerate() {
  35. iris.data[index] = part.parse::<f32>()?;
  36. }
  37. if let Some(name) = parts.next() {
  38. iris.name = name.into();
  39. } else {
  40. return Err(ParseError::Other("Missing name"))
  41. }
  42. Ok(iris)
  43. }
  44. }
  45. fn main() {
  46. // using Itertools::fold_results to create the result of parsing
  47. let irises = DATA.lines()
  48. .map(str::parse)
  49. .fold_ok(Vec::new(), |mut v, iris: Iris| {
  50. v.push(iris);
  51. v
  52. });
  53. let mut irises = match irises {
  54. Err(e) => {
  55. println!("Error parsing: {:?}", e);
  56. std::process::exit(1);
  57. }
  58. Ok(data) => data,
  59. };
  60. // Sort them and group them
  61. irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name));
  62. // using Iterator::cycle()
  63. let mut plot_symbols = "+ox".chars().cycle();
  64. let mut symbolmap = HashMap::new();
  65. // using Itertools::group_by
  66. for (species, species_group) in &irises.iter().group_by(|iris| &iris.name) {
  67. // assign a plot symbol
  68. symbolmap.entry(species).or_insert_with(|| {
  69. plot_symbols.next().unwrap()
  70. });
  71. println!("{} (symbol={})", species, symbolmap[species]);
  72. for iris in species_group {
  73. // using Itertools::format for lazy formatting
  74. println!("{:>3.1}", iris.data.iter().format(", "));
  75. }
  76. }
  77. // Look at all combinations of the four columns
  78. //
  79. // See https://en.wikipedia.org/wiki/Iris_flower_data_set
  80. //
  81. let n = 30; // plot size
  82. let mut plot = vec![' '; n * n];
  83. // using Itertools::tuple_combinations
  84. for (a, b) in (0..4).tuple_combinations() {
  85. println!("Column {} vs {}:", a, b);
  86. // Clear plot
  87. //
  88. // using std::iter::repeat;
  89. // using Itertools::set_from
  90. plot.iter_mut().set_from(repeat(' '));
  91. // using Itertools::minmax
  92. let min_max = |data: &[Iris], col| {
  93. data.iter()
  94. .map(|iris| iris.data[col])
  95. .minmax()
  96. .into_option()
  97. .expect("Can't find min/max of empty iterator")
  98. };
  99. let (min_x, max_x) = min_max(&irises, a);
  100. let (min_y, max_y) = min_max(&irises, b);
  101. // Plot the data points
  102. let round_to_grid = |x, min, max| ((x - min) / (max - min) * ((n - 1) as f32)) as usize;
  103. let flip = |ix| n - 1 - ix; // reverse axis direction
  104. for iris in &irises {
  105. let ix = round_to_grid(iris.data[a], min_x, max_x);
  106. let iy = flip(round_to_grid(iris.data[b], min_y, max_y));
  107. plot[n * iy + ix] = symbolmap[&iris.name];
  108. }
  109. // render plot
  110. //
  111. // using Itertools::join
  112. for line in plot.chunks(n) {
  113. println!("{}", line.iter().join(" "))
  114. }
  115. }
  116. }