From 53a6e9f0bda804d2caec17c8f73075e1220f3b1b Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Thu, 18 Jun 2020 22:02:01 -0400 Subject: [PATCH] Convert sum command into subcommand of the math command (#2004) * Convert sum command into subcommand of the math command * Add bullet points to math.md documentation --- crates/nu-cli/src/cli.rs | 2 +- crates/nu-cli/src/commands.rs | 4 +- crates/nu-cli/src/commands/each.rs | 2 +- crates/nu-cli/src/commands/math/average.rs | 4 +- crates/nu-cli/src/commands/math/command.rs | 24 +++- crates/nu-cli/src/commands/math/max.rs | 2 +- crates/nu-cli/src/commands/math/median.rs | 2 +- crates/nu-cli/src/commands/math/mod.rs | 2 + crates/nu-cli/src/commands/{ => math}/sum.rs | 81 ++++++------ crates/nu-cli/src/utils/data_processing.rs | 8 +- crates/nu-cli/tests/commands/drop.rs | 2 +- crates/nu-cli/tests/commands/each.rs | 2 +- crates/nu-cli/tests/commands/is_empty.rs | 6 +- crates/nu-cli/tests/commands/keep.rs | 2 +- crates/nu-cli/tests/commands/keep_until.rs | 2 +- crates/nu-cli/tests/commands/keep_while.rs | 2 +- crates/nu-cli/tests/commands/merge.rs | 2 +- crates/nu-cli/tests/commands/skip_until.rs | 2 +- crates/nu-cli/tests/commands/str_.rs | 4 +- crates/nu-cli/tests/commands/sum.rs | 10 +- crates/nu-cli/tests/commands/where_.rs | 6 +- crates/nu-test-support/src/lib.rs | 4 +- docs/commands/math.md | 129 +++++++++++-------- docs/commands/str.md | 2 +- docs/commands/sum.md | 10 +- tests/shell/pipeline/commands/internal.rs | 2 +- 26 files changed, 175 insertions(+), 143 deletions(-) rename crates/nu-cli/src/commands/{ => math}/sum.rs (50%) diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index e3cf9100ca..ab83a4a9d3 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -352,7 +352,7 @@ pub fn create_default_context( whole_stream_command(MathMedian), whole_stream_command(MathMinimum), whole_stream_command(MathMaximum), - whole_stream_command(Sum), + whole_stream_command(MathSummation), // File format output whole_stream_command(To), whole_stream_command(ToBSON), diff --git a/crates/nu-cli/src/commands.rs b/crates/nu-cli/src/commands.rs index d24be55728..cc79777f41 100644 --- a/crates/nu-cli/src/commands.rs +++ b/crates/nu-cli/src/commands.rs @@ -102,7 +102,6 @@ pub(crate) mod sort_by; pub(crate) mod split; pub(crate) mod split_by; pub(crate) mod str_; -pub(crate) mod sum; #[allow(unused)] pub(crate) mod t_sort_by; pub(crate) mod table; @@ -199,7 +198,7 @@ pub(crate) use lines::Lines; pub(crate) use ls::Ls; #[allow(unused_imports)] pub(crate) use map_max_by::MapMaxBy; -pub(crate) use math::{Math, MathAverage, MathMaximum, MathMedian, MathMinimum}; +pub(crate) use math::{Math, MathAverage, MathMaximum, MathMedian, MathMinimum, MathSummation}; pub(crate) use merge::Merge; pub(crate) use mkdir::Mkdir; pub(crate) use mv::Move; @@ -236,7 +235,6 @@ pub(crate) use str_::{ Str, StrCapitalize, StrDowncase, StrFindReplace, StrSet, StrSubstring, StrToDatetime, StrToDecimal, StrToInteger, StrTrim, StrUpcase, }; -pub(crate) use sum::Sum; #[allow(unused_imports)] pub(crate) use t_sort_by::TSortBy; pub(crate) use table::Table; diff --git a/crates/nu-cli/src/commands/each.rs b/crates/nu-cli/src/commands/each.rs index 10cae1a42f..76eb5adf63 100644 --- a/crates/nu-cli/src/commands/each.rs +++ b/crates/nu-cli/src/commands/each.rs @@ -56,7 +56,7 @@ impl WholeStreamCommand for Each { }, Example { description: "Echo the sum of each row", - example: "echo [[1 2] [3 4]] | each { echo $it | sum }", + example: "echo [[1 2] [3 4]] | each { echo $it | math sum }", result: Some(vec![ UntaggedValue::int(3).into(), UntaggedValue::int(7).into(), diff --git a/crates/nu-cli/src/commands/math/average.rs b/crates/nu-cli/src/commands/math/average.rs index 0e02ab1a3f..ecb111cd46 100644 --- a/crates/nu-cli/src/commands/math/average.rs +++ b/crates/nu-cli/src/commands/math/average.rs @@ -22,7 +22,7 @@ impl WholeStreamCommand for SubCommand { } fn usage(&self) -> &str { - "Gets the average of a list of numbers" + "Finds the average of a list of numbers or tables" } async fn run( @@ -56,7 +56,7 @@ impl WholeStreamCommand for SubCommand { } pub fn average(values: &[Value], name: &Tag) -> Result { - let sum = reducer_for(Reduce::Sum); + let sum = reducer_for(Reduce::Summation); let number = BigDecimal::from_usize(values.len()).ok_or_else(|| { ShellError::labeled_error( diff --git a/crates/nu-cli/src/commands/math/command.rs b/crates/nu-cli/src/commands/math/command.rs index 253220665d..b6609754c0 100644 --- a/crates/nu-cli/src/commands/math/command.rs +++ b/crates/nu-cli/src/commands/math/command.rs @@ -35,7 +35,7 @@ impl WholeStreamCommand for Command { mod tests { use super::*; use crate::commands::math::{ - average::average, max::maximum, min::minimum, utils::MathFunction, + average::average, max::maximum, min::minimum, sum::summation, utils::MathFunction, }; use nu_plugin::test_helpers::value::{decimal, int}; use nu_protocol::Value; @@ -67,31 +67,41 @@ mod tests { description: "Single value", values: vec![int(10)], expected_err: None, - expected_res: vec![Ok(decimal(10)), Ok(int(10)), Ok(int(10))], + expected_res: vec![Ok(decimal(10)), Ok(int(10)), Ok(int(10)), Ok(int(10))], }, TestCase { description: "Multiple Values", values: vec![int(10), int(30), int(20)], expected_err: None, - expected_res: vec![Ok(decimal(20)), Ok(int(10)), Ok(int(30))], + expected_res: vec![Ok(decimal(20)), Ok(int(10)), Ok(int(30)), Ok(int(60))], }, TestCase { description: "Mixed Values", values: vec![int(10), decimal(26.5), decimal(26.5)], expected_err: None, - expected_res: vec![Ok(decimal(21)), Ok(int(10)), Ok(decimal(26.5))], + expected_res: vec![ + Ok(decimal(21)), + Ok(int(10)), + Ok(decimal(26.5)), + Ok(decimal(63)), + ], }, TestCase { description: "Negative Values", values: vec![int(10), int(-11), int(-14)], expected_err: None, - expected_res: vec![Ok(decimal(-5)), Ok(int(-14)), Ok(int(10))], + expected_res: vec![Ok(decimal(-5)), Ok(int(-14)), Ok(int(10)), Ok(int(-15))], }, TestCase { description: "Mixed Negative Values", values: vec![int(10), decimal(-11.5), decimal(-13.5)], expected_err: None, - expected_res: vec![Ok(decimal(-5)), Ok(decimal(-13.5)), Ok(int(10))], + expected_res: vec![ + Ok(decimal(-5)), + Ok(decimal(-13.5)), + Ok(int(10)), + Ok(decimal(-15)), + ], }, // TODO-Uncomment once I figure out how to structure tables // TestCase { @@ -116,7 +126,7 @@ mod tests { for tc in tt.iter() { let tc: &TestCase = tc; // Just for type annotations - let math_functions: Vec = vec![average, minimum, maximum]; + let math_functions: Vec = vec![average, minimum, maximum, summation]; let results = math_functions .iter() .map(|mf| mf(&tc.values, &test_tag)) diff --git a/crates/nu-cli/src/commands/math/max.rs b/crates/nu-cli/src/commands/math/max.rs index db8b6ecd86..8d5354451f 100644 --- a/crates/nu-cli/src/commands/math/max.rs +++ b/crates/nu-cli/src/commands/math/max.rs @@ -18,7 +18,7 @@ impl WholeStreamCommand for SubCommand { } fn usage(&self) -> &str { - "Get the maximum of a list of numbers or tables" + "Finds the maximum within a list of numbers or tables" } async fn run( diff --git a/crates/nu-cli/src/commands/math/median.rs b/crates/nu-cli/src/commands/math/median.rs index 5a212be957..3748e0108a 100644 --- a/crates/nu-cli/src/commands/math/median.rs +++ b/crates/nu-cli/src/commands/math/median.rs @@ -121,7 +121,7 @@ pub fn median(values: &[Value], name: &Tag) -> Result { fn compute_average(values: &[Value], name: impl Into) -> Result { let name = name.into(); - let sum = reducer_for(Reduce::Sum); + let sum = reducer_for(Reduce::Summation); let number = BigDecimal::from_usize(2).ok_or_else(|| { ShellError::labeled_error( "could not convert to big decimal", diff --git a/crates/nu-cli/src/commands/math/mod.rs b/crates/nu-cli/src/commands/math/mod.rs index 2b0ae6d5da..399416fb65 100644 --- a/crates/nu-cli/src/commands/math/mod.rs +++ b/crates/nu-cli/src/commands/math/mod.rs @@ -3,6 +3,7 @@ pub mod command; pub mod max; pub mod median; pub mod min; +pub mod sum; pub mod utils; pub use average::SubCommand as MathAverage; @@ -10,3 +11,4 @@ pub use command::Command as Math; pub use max::SubCommand as MathMaximum; pub use median::SubCommand as MathMedian; pub use min::SubCommand as MathMinimum; +pub use sum::SubCommand as MathSummation; diff --git a/crates/nu-cli/src/commands/sum.rs b/crates/nu-cli/src/commands/math/sum.rs similarity index 50% rename from crates/nu-cli/src/commands/sum.rs rename to crates/nu-cli/src/commands/math/sum.rs index b326b72e0d..01fa5276cd 100644 --- a/crates/nu-cli/src/commands/sum.rs +++ b/crates/nu-cli/src/commands/math/sum.rs @@ -1,26 +1,25 @@ +use crate::commands::math::utils::calculate; use crate::commands::WholeStreamCommand; use crate::prelude::*; use crate::utils::data_processing::{reducer_for, Reduce}; use nu_errors::ShellError; -use nu_protocol::{Dictionary, ReturnSuccess, Signature, UntaggedValue, Value}; +use nu_protocol::{Dictionary, Signature, UntaggedValue, Value}; use num_traits::identities::Zero; -use indexmap::map::IndexMap; - -pub struct Sum; +pub struct SubCommand; #[async_trait] -impl WholeStreamCommand for Sum { +impl WholeStreamCommand for SubCommand { fn name(&self) -> &str { - "sum" + "math sum" } fn signature(&self) -> Signature { - Signature::build("sum") + Signature::build("math sum") } fn usage(&self) -> &str { - "Sums the values." + "Finds the sum of a list of numbers or tables" } async fn run( @@ -28,16 +27,19 @@ impl WholeStreamCommand for Sum { args: CommandArgs, registry: &CommandRegistry, ) -> Result { - sum(RunnableContext { - input: args.input, - registry: registry.clone(), - shell_manager: args.shell_manager, - host: args.host, - ctrl_c: args.ctrl_c, - current_errors: args.current_errors, - name: args.call_info.name_tag, - raw_input: args.raw_input, - }) + calculate( + RunnableContext { + input: args.input, + registry: registry.clone(), + shell_manager: args.shell_manager, + host: args.host, + ctrl_c: args.ctrl_c, + current_errors: args.current_errors, + name: args.call_info.name_tag, + raw_input: args.raw_input, + }, + summation, + ) .await } @@ -45,31 +47,28 @@ impl WholeStreamCommand for Sum { vec![ Example { description: "Sum a list of numbers", - example: "echo [1 2 3] | sum", + example: "echo [1 2 3] | math sum", result: Some(vec![UntaggedValue::int(6).into()]), }, Example { description: "Get the disk usage for the current directory", - example: "ls --all --du | get size | sum", + example: "ls --all --du | get size | math sum", result: None, }, ] } } -async fn sum( - RunnableContext { mut input, .. }: RunnableContext, -) -> Result { - let values: Vec = input.drain_vec().await; - let action = reducer_for(Reduce::Sum); +pub fn summation(values: &[Value], name: &Tag) -> Result { + let sum = reducer_for(Reduce::Summation); if values.iter().all(|v| v.is_primitive()) { - let total = action(Value::zero(), values)?; - Ok(OutputStream::one(ReturnSuccess::value(total))) + Ok(sum(Value::zero(), values.to_vec())?) } else { let mut column_values = IndexMap::new(); + for value in values { - if let UntaggedValue::Row(row_dict) = value.value { + if let UntaggedValue::Row(row_dict) = value.value.clone() { for (key, value) in row_dict.entries.iter() { column_values .entry(key.clone()) @@ -80,32 +79,28 @@ async fn sum( } let mut column_totals = IndexMap::new(); + for (col_name, col_vals) in column_values { - let sum = action(Value::zero(), col_vals); - match sum { - Ok(value) => { - column_totals.insert(col_name, value); - } - Err(err) => return Err(err), - }; + let sum = sum(Value::zero(), col_vals)?; + + column_totals.insert(col_name, sum); } - Ok(OutputStream::one(ReturnSuccess::value( - UntaggedValue::Row(Dictionary { - entries: column_totals, - }) - .into_untagged_value(), - ))) + + Ok(UntaggedValue::Row(Dictionary { + entries: column_totals, + }) + .into_value(name)) } } #[cfg(test)] mod tests { - use super::Sum; + use super::SubCommand; #[test] fn examples_work_as_expected() { use crate::examples::test as test_examples; - test_examples(Sum {}) + test_examples(SubCommand {}) } } diff --git a/crates/nu-cli/src/utils/data_processing.rs b/crates/nu-cli/src/utils/data_processing.rs index b17f714326..8b94f9047e 100644 --- a/crates/nu-cli/src/utils/data_processing.rs +++ b/crates/nu-cli/src/utils/data_processing.rs @@ -288,14 +288,14 @@ pub fn reducer_for( command: Reduce, ) -> Box) -> Result + Send + Sync + 'static> { match command { - Reduce::Sum | Reduce::Default => Box::new(formula(Value::zero(), Box::new(sum))), + Reduce::Summation | Reduce::Default => Box::new(formula(Value::zero(), Box::new(sum))), Reduce::Minimum => Box::new(|_, values| min(values)), Reduce::Maximum => Box::new(|_, values| max(values)), } } pub enum Reduce { - Sum, + Summation, Minimum, Maximum, Default, @@ -309,7 +309,7 @@ pub fn reduce( let tag = tag.into(); let reduce_with = match reducer { - Some(cmd) if cmd == "sum" => reducer_for(Reduce::Sum), + Some(cmd) if cmd == "sum" => reducer_for(Reduce::Summation), Some(cmd) if cmd == "min" => reducer_for(Reduce::Minimum), Some(cmd) if cmd == "max" => reducer_for(Reduce::Maximum), Some(_) | None => reducer_for(Reduce::Default), @@ -642,7 +642,7 @@ mod tests { fn reducer_computes_given_a_sum_command() -> Result<(), ShellError> { let subject = vec![int(1), int(1), int(1)]; - let action = reducer_for(Reduce::Sum); + let action = reducer_for(Reduce::Summation); assert_eq!(action(Value::zero(), subject)?, int(3)); diff --git a/crates/nu-cli/tests/commands/drop.rs b/crates/nu-cli/tests/commands/drop.rs index 1bdb26aac5..432f94f68f 100644 --- a/crates/nu-cli/tests/commands/drop.rs +++ b/crates/nu-cli/tests/commands/drop.rs @@ -4,7 +4,7 @@ use nu_test_support::nu; fn drop_rows() { let actual = nu!( cwd: "tests/fixtures/formats", - r#"echo '[{"foo": 3}, {"foo": 8}, {"foo": 4}]' | from json | drop 2 | get foo | sum | echo $it"# + r#"echo '[{"foo": 3}, {"foo": 8}, {"foo": 4}]' | from json | drop 2 | get foo | math sum | echo $it"# ); assert_eq!(actual.out, "3"); diff --git a/crates/nu-cli/tests/commands/each.rs b/crates/nu-cli/tests/commands/each.rs index bfffe2bf26..f12ffe3b62 100644 --- a/crates/nu-cli/tests/commands/each.rs +++ b/crates/nu-cli/tests/commands/each.rs @@ -5,7 +5,7 @@ fn each_works_separately() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" - echo [1 2 3] | each { echo $it 10 | sum } | to json | echo $it + echo [1 2 3] | each { echo $it 10 | math sum } | to json | echo $it "# )); diff --git a/crates/nu-cli/tests/commands/is_empty.rs b/crates/nu-cli/tests/commands/is_empty.rs index c53192f245..6929a58d04 100644 --- a/crates/nu-cli/tests/commands/is_empty.rs +++ b/crates/nu-cli/tests/commands/is_empty.rs @@ -22,7 +22,7 @@ fn adds_value_provided_if_column_is_empty() { open likes.csv | empty? likes 1 | get likes - | sum + | math sum | echo $it "# )); @@ -43,7 +43,7 @@ fn adds_value_provided_for_columns_that_are_empty() { {"boost": 1, "check": {}}, {"boost": null, "check": ["" {} [] ""]} ] - + "#, )]); @@ -53,7 +53,7 @@ fn adds_value_provided_for_columns_that_are_empty() { open checks.json | empty? boost check 1 | get boost check - | sum + | math sum | echo $it "# )); diff --git a/crates/nu-cli/tests/commands/keep.rs b/crates/nu-cli/tests/commands/keep.rs index 540566c8c2..eb50025197 100644 --- a/crates/nu-cli/tests/commands/keep.rs +++ b/crates/nu-cli/tests/commands/keep.rs @@ -22,7 +22,7 @@ fn rows() { open caballeros.csv | keep 3 | get lucky_code - | sum + | math sum | echo $it "# )); diff --git a/crates/nu-cli/tests/commands/keep_until.rs b/crates/nu-cli/tests/commands/keep_until.rs index 55524538b0..6dab4273d7 100644 --- a/crates/nu-cli/tests/commands/keep_until.rs +++ b/crates/nu-cli/tests/commands/keep_until.rs @@ -41,7 +41,7 @@ fn condition_is_met() { | keep-until "Chicken Collection" == "Red Chickens" | str to-int "31/04/2020" | get "31/04/2020" - | sum + | math sum | echo $it "# )); diff --git a/crates/nu-cli/tests/commands/keep_while.rs b/crates/nu-cli/tests/commands/keep_while.rs index e8c3e69342..87eeaade48 100644 --- a/crates/nu-cli/tests/commands/keep_while.rs +++ b/crates/nu-cli/tests/commands/keep_while.rs @@ -41,7 +41,7 @@ fn condition_is_met() { | keep-while "Chicken Collection" != "Blue Chickens" | str to-int "31/04/2020" | get "31/04/2020" - | sum + | math sum | echo $it "# )); diff --git a/crates/nu-cli/tests/commands/merge.rs b/crates/nu-cli/tests/commands/merge.rs index dfda69ee59..cda5a9178b 100644 --- a/crates/nu-cli/tests/commands/merge.rs +++ b/crates/nu-cli/tests/commands/merge.rs @@ -33,7 +33,7 @@ fn row() { | merge { open new_caballeros.csv } | where country in: ["Guayaquil Ecuador" "New Zealand"] | get luck - | sum + | math sum | echo $it "# )); diff --git a/crates/nu-cli/tests/commands/skip_until.rs b/crates/nu-cli/tests/commands/skip_until.rs index 4748766caa..1344f49d99 100644 --- a/crates/nu-cli/tests/commands/skip_until.rs +++ b/crates/nu-cli/tests/commands/skip_until.rs @@ -40,7 +40,7 @@ fn condition_is_met() { | skip-until "Chicken Collection" == "Red Chickens" | str to-int "31/04/2020" | get "31/04/2020" - | sum + | math sum | echo $it "# )); diff --git a/crates/nu-cli/tests/commands/str_.rs b/crates/nu-cli/tests/commands/str_.rs index e25e5df28f..3f2f574ac1 100644 --- a/crates/nu-cli/tests/commands/str_.rs +++ b/crates/nu-cli/tests/commands/str_.rs @@ -108,7 +108,7 @@ fn converts_to_decimal() { echo "3.1, 0.0415" | split row "," | str to-decimal - | sum + | math sum "# )); @@ -130,7 +130,7 @@ fn sets() { cwd: dirs.test(), pipeline( r#" open sample.toml - | str set wykittenshell package.name + | str set wykittenshell package.name | get package.name | echo $it "# diff --git a/crates/nu-cli/tests/commands/sum.rs b/crates/nu-cli/tests/commands/sum.rs index 5d5e440cdf..7395ef6cf8 100644 --- a/crates/nu-cli/tests/commands/sum.rs +++ b/crates/nu-cli/tests/commands/sum.rs @@ -25,7 +25,7 @@ fn all() { open meals.json | get meals | get calories - | sum + | math sum | echo $it "# )); @@ -53,7 +53,7 @@ fn outputs_zero_with_no_input() { let actual = nu!( cwd: dirs.test(), pipeline( r#" - sum + math sum | echo $it "# )); @@ -74,7 +74,7 @@ fn compute_sum_of_individual_row() -> Result<(), String> { for (column_name, expected_value) in answers_for_columns.iter() { let actual = nu!( cwd: "tests/fixtures/formats/", - format!("open sample-ps-output.json | select {} | sum | get {}", column_name, column_name) + format!("open sample-ps-output.json | select {} | math sum | get {}", column_name, column_name) ); let result = f64::from_str(&actual.out).map_err(|_| String::from("Failed to parse float."))?; @@ -95,7 +95,7 @@ fn compute_sum_of_table() -> Result<(), String> { for (column_name, expected_value) in answers_for_columns.iter() { let actual = nu!( cwd: "tests/fixtures/formats/", - format!("open sample-ps-output.json | select cpu mem virtual | sum | get {}", column_name) + format!("open sample-ps-output.json | select cpu mem virtual | math sum | get {}", column_name) ); let result = f64::from_str(&actual.out).map_err(|_| String::from("Failed to parse float."))?; @@ -108,7 +108,7 @@ fn compute_sum_of_table() -> Result<(), String> { fn sum_of_a_row_containing_a_table_is_an_error() { let actual = nu!( cwd: "tests/fixtures/formats/", - "open sample-sys-output.json | sum" + "open sample-sys-output.json | math sum" ); assert!(actual .err diff --git a/crates/nu-cli/tests/commands/where_.rs b/crates/nu-cli/tests/commands/where_.rs index 340828185e..41a0a59453 100644 --- a/crates/nu-cli/tests/commands/where_.rs +++ b/crates/nu-cli/tests/commands/where_.rs @@ -14,7 +14,7 @@ fn filters_by_unit_size_comparison() { fn filters_with_nothing_comparison() { let actual = nu!( cwd: "tests/fixtures/formats", - r#"echo '[{"foo": 3}, {"foo": null}, {"foo": 4}]' | from json | get foo | compact | where $it > 1 | sum | echo $it"# + r#"echo '[{"foo": 3}, {"foo": null}, {"foo": 4}]' | from json | get foo | compact | where $it > 1 | math sum | echo $it"# ); assert_eq!(actual.out, "7"); @@ -24,7 +24,7 @@ fn filters_with_nothing_comparison() { fn where_in_table() { let actual = nu!( cwd: "tests/fixtures/formats", - r#"echo '[{"name": "foo", "size": 3}, {"name": "foo", "size": 2}, {"name": "bar", "size": 4}]' | from json | where name in: ["foo"] | get size | sum | echo $it"# + r#"echo '[{"name": "foo", "size": 3}, {"name": "foo", "size": 2}, {"name": "bar", "size": 4}]' | from json | where name in: ["foo"] | get size | math sum | echo $it"# ); assert_eq!(actual.out, "5"); @@ -34,7 +34,7 @@ fn where_in_table() { fn where_not_in_table() { let actual = nu!( cwd: "tests/fixtures/formats", - r#"echo '[{"name": "foo", "size": 3}, {"name": "foo", "size": 2}, {"name": "bar", "size": 4}]' | from json | where name not-in: ["foo"] | get size | sum | echo $it"# + r#"echo '[{"name": "foo", "size": 3}, {"name": "foo", "size": 2}, {"name": "bar", "size": 4}]' | from json | where name not-in: ["foo"] | get size | math sum | echo $it"# ); assert_eq!(actual.out, "4"); diff --git a/crates/nu-test-support/src/lib.rs b/crates/nu-test-support/src/lib.rs index 8850dce034..a60b75217c 100644 --- a/crates/nu-test-support/src/lib.rs +++ b/crates/nu-test-support/src/lib.rs @@ -36,14 +36,14 @@ mod tests { | from-csv | get rusty_luck | str --to-int - | sum + | math sum | echo "$it" "#, ); assert_eq!( actual, - r#"open los_tres_amigos.txt | from-csv | get rusty_luck | str --to-int | sum | echo "$it""# + r#"open los_tres_amigos.txt | from-csv | get rusty_luck | str --to-int | math sum | echo "$it""# ); } } diff --git a/docs/commands/math.md b/docs/commands/math.md index a9eba76aa2..0af856efcd 100644 --- a/docs/commands/math.md +++ b/docs/commands/math.md @@ -1,95 +1,126 @@ # math + Mathematical functions that generally only operate on a list of numbers (integers, decimals, bytes) and tables. Currently the following functions are implemented: -`math average` Get the average of a list of number -`math min` Get the minimum of a list of numbers -`math max` Get the maximum of a list of numbers + +* `math average`: Finds the average of a list of numbers or tables +* `math min`: Finds the minimum within a list of numbers or tables +* `math max`: Finds the maximum within a list of numbers or tables +* `math sum`: Finds the sum of a list of numbers or tables However, the mathematical functions like `min` and `max` are more permissive and also work on `Dates`. ## Examples + To get the average of the file sizes in a directory, simply pipe the size column from the ls command to the average command. ### List of Numbers (Integers, Decimals, Bytes) + ```shell > ls - # │ name │ type │ size │ modified + # │ name │ type │ size │ modified ────┼────────────────────┼──────┼──────────┼───────────── - 0 │ CODE_OF_CONDUCT.md │ File │ 3.4 KB │ 4 days ago - 1 │ CONTRIBUTING.md │ File │ 1.3 KB │ 4 days ago - 2 │ Cargo.lock │ File │ 106.3 KB │ 6 mins ago - 3 │ Cargo.toml │ File │ 4.6 KB │ 3 days ago - 4 │ LICENSE │ File │ 1.1 KB │ 4 days ago - 5 │ Makefile.toml │ File │ 449 B │ 4 days ago - 6 │ README.md │ File │ 16.0 KB │ 6 mins ago - 7 │ TODO.md │ File │ 0 B │ 6 mins ago - 8 │ assets │ Dir │ 128 B │ 4 days ago - 9 │ build.rs │ File │ 78 B │ 4 days ago - 10 │ crates │ Dir │ 672 B │ 3 days ago - 11 │ debian │ Dir │ 352 B │ 4 days ago - 12 │ docker │ Dir │ 288 B │ 4 days ago - 13 │ docs │ Dir │ 160 B │ 4 days ago - 14 │ features.toml │ File │ 632 B │ 4 days ago - 15 │ images │ Dir │ 160 B │ 4 days ago - 16 │ justfile │ File │ 234 B │ 3 days ago - 17 │ rustfmt.toml │ File │ 16 B │ 4 days ago - 18 │ src │ Dir │ 128 B │ 4 days ago - 19 │ target │ Dir │ 192 B │ 8 hours ago - 20 │ tests │ Dir │ 192 B │ 4 days ago + 0 │ CODE_OF_CONDUCT.md │ File │ 3.4 KB │ 4 days ago + 1 │ CONTRIBUTING.md │ File │ 1.3 KB │ 4 days ago + 2 │ Cargo.lock │ File │ 106.3 KB │ 6 mins ago + 3 │ Cargo.toml │ File │ 4.6 KB │ 3 days ago + 4 │ LICENSE │ File │ 1.1 KB │ 4 days ago + 5 │ Makefile.toml │ File │ 449 B │ 4 days ago + 6 │ README.md │ File │ 16.0 KB │ 6 mins ago + 7 │ TODO.md │ File │ 0 B │ 6 mins ago + 8 │ assets │ Dir │ 128 B │ 4 days ago + 9 │ build.rs │ File │ 78 B │ 4 days ago + 10 │ crates │ Dir │ 672 B │ 3 days ago + 11 │ debian │ Dir │ 352 B │ 4 days ago + 12 │ docker │ Dir │ 288 B │ 4 days ago + 13 │ docs │ Dir │ 160 B │ 4 days ago + 14 │ features.toml │ File │ 632 B │ 4 days ago + 15 │ images │ Dir │ 160 B │ 4 days ago + 16 │ justfile │ File │ 234 B │ 3 days ago + 17 │ rustfmt.toml │ File │ 16 B │ 4 days ago + 18 │ src │ Dir │ 128 B │ 4 days ago + 19 │ target │ Dir │ 192 B │ 8 hours ago + 20 │ tests │ Dir │ 192 B │ 4 days ago +``` +```shell > ls | get size | math average ───┬──────── - 0 │ 6.5 KB + 0 │ 7.2 KB ───┴──────── +``` +```shell > ls | get size | math min ───┬───── - 0 │ 0 B + 0 │ 0 B ───┴───── +``` + +```shell > ls | get size | math max ───┬────────── - 0 │ 106.3 KB + 0 │ 113.5 KB ───┴────────── +``` -# Dates +```shell +> ls | get size | math sum +───┬────────── + 0 │ 143.4 KB +───┴────────── +``` + +### Dates + +```shell > ls | get modified | math min 2020-06-09 17:25:51.798743222 UTC +``` +```shell > ls | get modified | math max 2020-06-14 05:49:59.637449186 UT ``` ### Operations on tables -```shell -> pwd | split row / | size -───┬───────┬───────┬───────┬──────────── - # │ lines │ words │ chars │ max length -───┼───────┼───────┼───────┼──────────── - 0 │ 0 │ 1 │ 5 │ 5 - 1 │ 0 │ 1 │ 7 │ 7 - 2 │ 0 │ 1 │ 9 │ 9 - 3 │ 0 │ 1 │ 7 │ 7 -───┴───────┴───────┴───────┴──────────── +```shell +> pwd | split row / | size +───┬───────┬───────┬───────┬──────────── + # │ lines │ words │ chars │ max length +───┼───────┼───────┼───────┼──────────── + 0 │ 0 │ 1 │ 5 │ 5 + 1 │ 0 │ 1 │ 7 │ 7 + 2 │ 0 │ 1 │ 9 │ 9 + 3 │ 0 │ 1 │ 7 │ 7 +───┴───────┴───────┴───────┴──────────── +``` + +```shell > pwd | split row / | size | math max ───────────┬─── - lines │ 0 - words │ 1 - chars │ 9 - max length │ 9 + lines │ 0 + words │ 1 + chars │ 9 + max length │ 9 ────────────┴─── +``` +```shell > pwd | split row / | size | math average ────────────┬──────── - lines │ 0.0000 - words │ 1.0000 - chars │ 7.0000 - max length │ 7.0000 + lines │ 0.0000 + words │ 1.0000 + chars │ 7.0000 + max length │ 7.0000 ────────────┴──────── ``` ## Errors + `math` functions are aggregation functions so empty lists are invalid + ```shell > echo [] | math average error: Error: Unexpected: Cannot perform aggregate math operation on empty data @@ -102,7 +133,3 @@ then unexpected results can occur. > echo [1 2 a ] | math average 0 ``` - - - - diff --git a/docs/commands/str.md b/docs/commands/str.md index ce358043db..f8eb32c475 100644 --- a/docs/commands/str.md +++ b/docs/commands/str.md @@ -41,7 +41,7 @@ Applies the subcommand to a value or a table. 1 │ │ filesystem │ ━━━┷━━━┷━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -> echo "1, 2, 3" | split row "," | str to-int | sum +> echo "1, 2, 3" | split row "," | str to-int | math sum ━━━━━━━━━ ───────── diff --git a/docs/commands/sum.md b/docs/commands/sum.md index e87dc65afb..f36d5b2655 100644 --- a/docs/commands/sum.md +++ b/docs/commands/sum.md @@ -5,7 +5,7 @@ This command allows you to calculate the sum of values in a column. To get the sum of the file sizes in a directory, simply pipe the size column from the ls command to the sum command. ```shell -> ls | get size | sum +> ls | get size | math sum ━━━━━━━━━ value ━━━━━━━━━ @@ -15,7 +15,7 @@ To get the sum of the file sizes in a directory, simply pipe the size column fro To get the sum of the characters that make up your present working directory. ```shell -> pwd | split-row / | size | get chars | sum +> pwd | split-row / | size | get chars | math sum ━━━━━━━━━ ━━━━━━━━━ @@ -27,15 +27,15 @@ Note that sum only works for integer and byte values. If the shell doesn't recog One way to solve this is to convert each row to an integer when possible and then pipe the result to `sum` ```shell -> open tests/fixtures/formats/caco3_plastics.csv | get tariff_item | sum +> open tests/fixtures/formats/caco3_plastics.csv | get tariff_item | math sum error: Unrecognized type in stream: Primitive(String("2509000000")) - shell:1:0 -1 | open tests/fixtures/formats/caco3_plastics.csv | get tariff_item | sum +1 | open tests/fixtures/formats/caco3_plastics.csv | get tariff_item | math sum | ^^^^ source ``` ```shell -> open tests/fixtures/formats/caco3_plastics.csv | get tariff_item | str --to-int | sum +> open tests/fixtures/formats/caco3_plastics.csv | get tariff_item | str --to-int | math sum ━━━━━━━━━━━━━ ───────────── diff --git a/tests/shell/pipeline/commands/internal.rs b/tests/shell/pipeline/commands/internal.rs index d5ebf7da8a..d30718cf6e 100644 --- a/tests/shell/pipeline/commands/internal.rs +++ b/tests/shell/pipeline/commands/internal.rs @@ -198,7 +198,7 @@ fn echoing_ranges() { let actual = nu!( cwd: ".", r#" - echo 1..3 | sum + echo 1..3 | math sum "# );