Prevents duplicate fields in transpose -r (#5840)

This commit is contained in:
pwygab 2022-06-23 08:19:06 +08:00 committed by GitHub
parent 0827ed143d
commit f43a65d7a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 126 additions and 4 deletions

View file

@ -15,6 +15,8 @@ pub struct TransposeArgs {
header_row: bool,
ignore_titles: bool,
as_record: bool,
keep_last: bool,
keep_all: bool,
}
impl Command for Transpose {
@ -39,6 +41,16 @@ impl Command for Transpose {
"transfer to record if the result is a table and contains only one row",
Some('d'),
)
.switch(
"keep-last",
"on repetition of record fields due to `header-row`, keep the last value obtained",
Some('l'),
)
.switch(
"keep-all",
"on repetition of record fields due to `header-row`, keep all the values obtained",
Some('a'),
)
.rest(
"rest",
SyntaxShape::String,
@ -149,6 +161,8 @@ pub fn transpose(
header_row: call.has_flag("header-row"),
ignore_titles: call.has_flag("ignore-titles"),
as_record: call.has_flag("as-record"),
keep_last: call.has_flag("keep-last"),
keep_all: call.has_flag("keep-all"),
rest: call.rest(engine_state, stack, 0)?,
};
@ -240,12 +254,82 @@ pub fn transpose(
for i in input.clone() {
match &i.get_data_by_key(&desc) {
Some(x) => {
cols.push(headers[column_num].clone());
vals.push(x.clone());
if args.keep_all && cols.contains(&headers[column_num]) {
let index = cols
.iter()
.position(|y| y == &headers[column_num])
.expect("value is contained.");
let new_val = match &vals[index] {
Value::List { vals, span } => {
let mut vals = vals.clone();
vals.push(x.clone());
Value::List {
vals: vals.to_vec(),
span: *span,
}
}
v => Value::List {
vals: vec![v.clone(), x.clone()],
span: v.span().expect("this should be a valid span"),
},
};
cols.remove(index);
vals.remove(index);
cols.push(headers[column_num].clone());
vals.push(new_val);
} else if args.keep_last && cols.contains(&headers[column_num]) {
let index = cols
.iter()
.position(|y| y == &headers[column_num])
.expect("value is contained.");
cols.remove(index);
vals.remove(index);
cols.push(headers[column_num].clone());
vals.push(x.clone());
} else if !cols.contains(&headers[column_num]) {
cols.push(headers[column_num].clone());
vals.push(x.clone());
}
}
_ => {
cols.push(headers[column_num].clone());
vals.push(Value::nothing(name));
if args.keep_all && cols.contains(&headers[column_num]) {
let index = cols
.iter()
.position(|y| y == &headers[column_num])
.expect("value is contained.");
let new_val = match &vals[index] {
Value::List { vals, span } => {
let mut vals = vals.clone();
vals.push(Value::nothing(name));
Value::List {
vals: vals.to_vec(),
span: *span,
}
}
v => Value::List {
vals: vec![v.clone(), Value::nothing(name)],
span: v.span().expect("this should be a valid span"),
},
};
cols.remove(index);
vals.remove(index);
cols.push(headers[column_num].clone());
vals.push(new_val);
} else if args.keep_last && cols.contains(&headers[column_num]) {
let index = cols
.iter()
.position(|y| y == &headers[column_num])
.expect("value is contained.");
cols.remove(index);
vals.remove(index);
cols.push(headers[column_num].clone());
vals.push(Value::nothing(name));
} else if !cols.contains(&headers[column_num]) {
cols.push(headers[column_num].clone());
vals.push(Value::nothing(name));
}
}
}
column_num += 1;

View file

@ -65,6 +65,7 @@ mod split_row;
mod str_;
mod take;
mod touch;
mod transpose;
mod uniq;
mod update;
mod upsert;

View file

@ -0,0 +1,37 @@
use nu_test_support::{nu, pipeline};
#[test]
fn row() {
let actual = nu!(
cwd: ".", pipeline(
r#"
[[key value]; [foo 1] [foo 2]] | transpose -r | debug
"#
));
assert!(actual.out.contains("foo: 1"));
}
#[test]
fn row_but_last() {
let actual = nu!(
cwd: ".", pipeline(
r#"
[[key value]; [foo 1] [foo 2]] | transpose -r -l | debug
"#
));
assert!(actual.out.contains("foo: 2"));
}
#[test]
fn row_but_all() {
let actual = nu!(
cwd: ".", pipeline(
r#"
[[key value]; [foo 1] [foo 2]] | transpose -r -a | debug
"#
));
assert!(actual.out.contains("foo: [1, 2]"));
}