mirror of
https://github.com/nushell/nushell.git
synced 2025-04-29 07:34:28 +02:00
Allow dropping columns. (#3107)
`drop` is used for removing the last row. Passing a number allows dropping N rows. Here we introduce the same logic for dropping columns instead. You can certainly remove columns by using `reject`, however, there could be cases where we are interested in removing columns from tables that contain, say, a big number of columns. Using `reject` becomes impractical, especially when you don't care about the column names that could either be known or not known when exploring tables. ``` > echo [[lib, extension]; [nu-core, rs] [rake, rb]] ─────────┬─────────── lib │ extension ─────────┼─────────── nu-core │ rs rake │ rb ─────────┴─────────── ``` ``` > echo [[lib, extension]; [nu-core, rs] [rake, rb]] | drop column ───────── lib ───────── nu-core rake ───────── ```
This commit is contained in:
parent
84169a91ff
commit
19d5f782cc
@ -163,7 +163,7 @@ pub(crate) use def::Def;
|
|||||||
pub(crate) use default::Default;
|
pub(crate) use default::Default;
|
||||||
pub(crate) use describe::Describe;
|
pub(crate) use describe::Describe;
|
||||||
pub(crate) use do_::Do;
|
pub(crate) use do_::Do;
|
||||||
pub(crate) use drop::Drop;
|
pub(crate) use drop::{Drop, DropColumn};
|
||||||
pub(crate) use du::Du;
|
pub(crate) use du::Du;
|
||||||
pub(crate) use each::Each;
|
pub(crate) use each::Each;
|
||||||
pub(crate) use each::EachGroup;
|
pub(crate) use each::EachGroup;
|
||||||
|
@ -114,6 +114,7 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
|||||||
whole_stream_command(AnsiStrip),
|
whole_stream_command(AnsiStrip),
|
||||||
whole_stream_command(Char),
|
whole_stream_command(Char),
|
||||||
// Column manipulation
|
// Column manipulation
|
||||||
|
whole_stream_command(DropColumn),
|
||||||
whole_stream_command(Move),
|
whole_stream_command(Move),
|
||||||
whole_stream_command(Reject),
|
whole_stream_command(Reject),
|
||||||
whole_stream_command(Select),
|
whole_stream_command(Select),
|
||||||
|
86
crates/nu-command/src/commands/drop/column.rs
Normal file
86
crates/nu-command/src/commands/drop/column.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
use nu_data::base::select_fields;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
|
use nu_errors::ShellError;
|
||||||
|
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape};
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct Arguments {
|
||||||
|
columns: Option<Tagged<u64>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl WholeStreamCommand for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"drop column"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("drop column").optional(
|
||||||
|
"columns",
|
||||||
|
SyntaxShape::Number,
|
||||||
|
"starting from the end, the number of columns to remove",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Remove the last number of columns. If you want to remove columns by name, try 'reject'."
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
drop(args).await
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
use nu_protocol::{row, Value};
|
||||||
|
|
||||||
|
vec![Example {
|
||||||
|
description: "Remove the last column of a table",
|
||||||
|
example: "echo [[lib, extension]; [nu-lib, rs] [nu-core, rb]] | drop column",
|
||||||
|
result: Some(vec![
|
||||||
|
row! { "lib".into() => Value::from("nu-lib") },
|
||||||
|
row! { "lib".into() => Value::from("nu-core") },
|
||||||
|
]),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn drop(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
let (Arguments { columns }, input) = args.process().await?;
|
||||||
|
|
||||||
|
let to_drop = if let Some(quantity) = columns {
|
||||||
|
*quantity as usize
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(input
|
||||||
|
.map(move |item| {
|
||||||
|
let headers = item.data_descriptors();
|
||||||
|
|
||||||
|
let descs = match headers.len() {
|
||||||
|
0 => &headers[..],
|
||||||
|
n if to_drop > n => &[],
|
||||||
|
n => &headers[..n - to_drop],
|
||||||
|
};
|
||||||
|
|
||||||
|
select_fields(&item, descs, item.tag())
|
||||||
|
})
|
||||||
|
.map(ReturnSuccess::value)
|
||||||
|
.to_output_stream())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||||
|
use crate::examples::test as test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
@ -4,15 +4,15 @@ use nu_errors::ShellError;
|
|||||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub struct Drop;
|
pub struct Command;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct DropArgs {
|
pub struct Arguments {
|
||||||
rows: Option<Tagged<u64>>,
|
rows: Option<Tagged<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl WholeStreamCommand for Drop {
|
impl WholeStreamCommand for Command {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"drop"
|
"drop"
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ impl WholeStreamCommand for Drop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Remove the last number of rows. If you want to remove columns, try 'reject'."
|
"Remove the last number of rows. If you want to remove columns, try 'drop column'."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
@ -53,7 +53,7 @@ impl WholeStreamCommand for Drop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn drop(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
async fn drop(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (DropArgs { rows }, input) = args.process().await?;
|
let (Arguments { rows }, input) = args.process().await?;
|
||||||
let v: Vec<_> = input.into_vec().await;
|
let v: Vec<_> = input.into_vec().await;
|
||||||
|
|
||||||
let rows_to_drop = if let Some(quantity) = rows {
|
let rows_to_drop = if let Some(quantity) = rows {
|
||||||
@ -76,16 +76,3 @@ async fn drop(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
futures::stream::iter(iter).to_output_stream()
|
futures::stream::iter(iter).to_output_stream()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::Drop;
|
|
||||||
use super::ShellError;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
|
||||||
use crate::examples::test as test_examples;
|
|
||||||
|
|
||||||
test_examples(Drop {})
|
|
||||||
}
|
|
||||||
}
|
|
5
crates/nu-command/src/commands/drop/mod.rs
Normal file
5
crates/nu-command/src/commands/drop/mod.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
mod column;
|
||||||
|
mod command;
|
||||||
|
|
||||||
|
pub use column::SubCommand as DropColumn;
|
||||||
|
pub use command::Command as Drop;
|
@ -1,23 +1,68 @@
|
|||||||
use nu_test_support::{nu, pipeline};
|
use nu_test_support::{nu, pipeline};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drop_rows() {
|
fn columns() {
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: "tests/fixtures/formats",
|
cwd: ".", pipeline(r#"
|
||||||
r#"echo '[{"foo": 3}, {"foo": 8}, {"foo": 4}]' | from json | drop 2 | get foo | math sum "#
|
echo [
|
||||||
|
[arepas, color];
|
||||||
|
|
||||||
|
[3, white]
|
||||||
|
[8, yellow]
|
||||||
|
[4, white]
|
||||||
|
]
|
||||||
|
| drop column
|
||||||
|
| get
|
||||||
|
| count
|
||||||
|
"#)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(actual.out, "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn more_columns_than_table_has() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".", pipeline(r#"
|
||||||
|
echo [
|
||||||
|
[arepas, color];
|
||||||
|
|
||||||
|
[3, white]
|
||||||
|
[8, yellow]
|
||||||
|
[4, white]
|
||||||
|
]
|
||||||
|
| drop column 3
|
||||||
|
| get
|
||||||
|
| empty?
|
||||||
|
"#)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(actual.out, "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rows() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".", pipeline(r#"
|
||||||
|
echo [
|
||||||
|
[arepas];
|
||||||
|
|
||||||
|
[3]
|
||||||
|
[8]
|
||||||
|
[4]
|
||||||
|
]
|
||||||
|
| drop 2
|
||||||
|
| get arepas
|
||||||
|
| math sum
|
||||||
|
"#)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(actual.out, "3");
|
assert_eq!(actual.out, "3");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drop_more_rows_than_table_has() {
|
fn more_rows_than_table_has() {
|
||||||
let actual = nu!(
|
let actual = nu!(cwd: ".", "date | drop 50 | count");
|
||||||
cwd: ".", pipeline(
|
|
||||||
r#"
|
|
||||||
date | drop 50 | count
|
|
||||||
"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "0");
|
assert_eq!(actual.out, "0");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user