mirror of
https://github.com/nushell/nushell.git
synced 2025-01-11 08:48:23 +01:00
# Description `uniq -i` does not convert output strings to lowercase. Also, `uniq -i` did not ignore case in strings below the first level of Tables and Records. Now all strings case are ignored for all children Values for tables, Records, and List. Fixes https://github.com/nushell/nushell/issues/7192 # Tests + Formatting About the issue https://github.com/nushell/nushell/issues/7192, the output will be: ``` 〉[AAA BBB CCC] | uniq -i ╭───┬─────╮ │ 0 │ AAA │ │ 1 │ BBB │ │ 2 │ CCC │ ╰───┴─────╯ ``` About ignoring case for all children string, I expect this to be true: ``` ([[origin, people]; [World, ( [[name, meal]; ['Geremias', {plate: 'bitoque', carbs: 100}] ] )], [World, ( [[name, meal]; ['Martin', {plate: 'bitoque', carbs: 100}] ] )], [World, ( [[name, meal]; ['Geremias', {plate: 'Bitoque', carbs: 100}] ] )], ] | uniq -i ) == ([[origin, people]; [World, ( [[name, meal]; ['Geremias', {plate: 'bitoque', carbs: 100}] ] )], [World, ( [[name, meal]; ['Martin', {plate: 'bitoque', carbs: 100}] ] )] ]) ```
This commit is contained in:
parent
c3c3481ef5
commit
651e86a3c0
@ -123,25 +123,68 @@ impl Command for Uniq {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_lowercase(value: nu_protocol::Value) -> nu_protocol::Value {
|
||||
match value {
|
||||
Value::String { val: s, span } => Value::String {
|
||||
val: s.to_lowercase(),
|
||||
span,
|
||||
},
|
||||
other => other,
|
||||
struct ValueCounter {
|
||||
val: Value,
|
||||
val_to_compare: Value,
|
||||
count: i64,
|
||||
}
|
||||
|
||||
impl PartialEq<Self> for ValueCounter {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.val == other.val
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_results_with_count(head: Span, uniq_values: Vec<(Value, i64)>) -> Vec<Value> {
|
||||
impl ValueCounter {
|
||||
fn new(val: Value, flag_ignore_case: bool) -> Self {
|
||||
ValueCounter {
|
||||
val: val.clone(),
|
||||
val_to_compare: if flag_ignore_case {
|
||||
clone_to_lowercase(&val)
|
||||
} else {
|
||||
val
|
||||
},
|
||||
count: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_to_lowercase(value: &Value) -> Value {
|
||||
match value {
|
||||
Value::String { val: s, span } => Value::String {
|
||||
val: s.clone().to_lowercase(),
|
||||
span: *span,
|
||||
},
|
||||
Value::List { vals: vec, span } => Value::List {
|
||||
vals: vec
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|v| clone_to_lowercase(&v))
|
||||
.collect(),
|
||||
span: *span,
|
||||
},
|
||||
Value::Record { cols, vals, span } => Value::Record {
|
||||
cols: cols.clone(),
|
||||
vals: vals
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|v| clone_to_lowercase(&v))
|
||||
.collect(),
|
||||
span: *span,
|
||||
},
|
||||
other => other.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_results_with_count(head: Span, uniq_values: Vec<ValueCounter>) -> Vec<Value> {
|
||||
uniq_values
|
||||
.into_iter()
|
||||
.map(|item| Value::Record {
|
||||
cols: vec!["value".to_string(), "count".to_string()],
|
||||
vals: vec![
|
||||
item.0,
|
||||
item.val,
|
||||
Value::Int {
|
||||
val: item.1,
|
||||
val: item.count,
|
||||
span: head,
|
||||
},
|
||||
],
|
||||
@ -165,33 +208,30 @@ fn uniq(
|
||||
|
||||
let mut uniq_values = input
|
||||
.into_iter()
|
||||
.map(|item| {
|
||||
if flag_ignore_case {
|
||||
to_lowercase(item)
|
||||
} else {
|
||||
item
|
||||
}
|
||||
})
|
||||
.fold(Vec::<(Value, i64)>::new(), |mut counter, item| {
|
||||
match counter.iter_mut().find(|x| x.0 == item) {
|
||||
Some(x) => x.1 += 1,
|
||||
None => counter.push((item, 1)),
|
||||
.map(|item| ValueCounter::new(item, flag_ignore_case))
|
||||
.fold(Vec::<ValueCounter>::new(), |mut counter, item| {
|
||||
match counter
|
||||
.iter_mut()
|
||||
.find(|x| x.val_to_compare == item.val_to_compare)
|
||||
{
|
||||
Some(x) => x.count += 1,
|
||||
None => counter.push(item),
|
||||
};
|
||||
counter
|
||||
});
|
||||
|
||||
if flag_show_repeated {
|
||||
uniq_values.retain(|value_count_pair| value_count_pair.1 > 1);
|
||||
uniq_values.retain(|value_count_pair| value_count_pair.count > 1);
|
||||
}
|
||||
|
||||
if flag_only_uniques {
|
||||
uniq_values.retain(|value_count_pair| value_count_pair.1 == 1);
|
||||
uniq_values.retain(|value_count_pair| value_count_pair.count == 1);
|
||||
}
|
||||
|
||||
let result = if flag_show_count {
|
||||
generate_results_with_count(head, uniq_values)
|
||||
} else {
|
||||
uniq_values.into_iter().map(|v| v.0).collect()
|
||||
uniq_values.into_iter().map(|v| v.val).collect()
|
||||
};
|
||||
|
||||
Ok(Value::List {
|
||||
|
@ -232,11 +232,11 @@ fn uniq_simple_vals_strs() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_table() {
|
||||
fn table() {
|
||||
let actual = nu!(
|
||||
cwd: "tests/fixtures/formats", pipeline(
|
||||
r#"
|
||||
[[fruit day]; [apple monday] [apple friday] [apple monday] [pear monday] [orange tuesday]]
|
||||
[[fruit day]; [apple monday] [apple friday] [Apple friday] [apple monday] [pear monday] [orange tuesday]]
|
||||
| uniq
|
||||
"#
|
||||
));
|
||||
@ -244,10 +244,59 @@ fn with_table() {
|
||||
let expected = nu!(
|
||||
cwd: "tests/fixtures/formats", pipeline(
|
||||
r#"
|
||||
echo [[fruit day]; [apple monday] [apple friday] [pear monday] [orange tuesday]]
|
||||
echo [[fruit day]; [apple monday] [apple friday] [Apple friday] [pear monday] [orange tuesday]]
|
||||
"#
|
||||
));
|
||||
print!("{}", actual.out);
|
||||
print!("{}", expected.out);
|
||||
assert_eq!(actual.out, expected.out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn table_with_ignore_case() {
|
||||
let actual = nu!(
|
||||
cwd: "tests/fixtures/formats", pipeline(
|
||||
r#"
|
||||
[[origin, people];
|
||||
[World, (
|
||||
[[name, meal];
|
||||
['Geremias', {plate: 'bitoque', carbs: 100}]
|
||||
]
|
||||
)],
|
||||
[World, (
|
||||
[[name, meal];
|
||||
['Martin', {plate: 'bitoque', carbs: 100}]
|
||||
]
|
||||
)],
|
||||
[World, (
|
||||
[[name, meal];
|
||||
['Geremias', {plate: 'Bitoque', carbs: 100}]
|
||||
]
|
||||
)],
|
||||
] | uniq -i
|
||||
"#
|
||||
));
|
||||
|
||||
let expected = nu!(
|
||||
cwd: "tests/fixtures/formats", pipeline(
|
||||
r#"
|
||||
echo [[origin, people];
|
||||
[World, (
|
||||
[[name, meal];
|
||||
['Geremias', {plate: 'bitoque', carbs: 100}]
|
||||
]
|
||||
)],
|
||||
[World, (
|
||||
[[name, meal];
|
||||
['Martin', {plate: 'bitoque', carbs: 100}]
|
||||
]
|
||||
)],
|
||||
]
|
||||
"#
|
||||
));
|
||||
|
||||
print!("{}", actual.out);
|
||||
print!("{}", expected.out);
|
||||
assert_eq!(actual.out, expected.out);
|
||||
assert_eq!(actual.out, expected.out);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user