1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
use crate::prelude::*; use nu_engine::WholeStreamCommand; use nu_errors::ShellError; use nu_protocol::{Signature, UntaggedValue}; pub struct Uniq; impl WholeStreamCommand for Uniq { fn name(&self) -> &str { "uniq" } fn signature(&self) -> Signature { Signature::build("uniq").switch("count", "Count the unique rows", Some('c')) } fn usage(&self) -> &str { "Return the unique rows." } fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> { uniq(args) } fn examples(&self) -> Vec<Example> { vec![ Example { description: "Remove duplicate rows of a list/table", example: "echo [2 3 3 4] | uniq", result: Some(vec![ UntaggedValue::int(2).into(), UntaggedValue::int(3).into(), UntaggedValue::int(4).into(), ]), }, Example { description: "Remove duplicate rows and show counts of a list/table", example: "echo [1 2 2] | uniq -c", result: Some(vec![ UntaggedValue::row(indexmap! { "value".to_string() => UntaggedValue::int(1).into(), "count".to_string() => UntaggedValue::int(1).into(), }) .into(), UntaggedValue::row(indexmap! { "value".to_string() => UntaggedValue::int(2).into(), "count".to_string() => UntaggedValue::int(2).into(), }) .into(), ]), }, ] } } fn uniq(args: CommandArgs) -> Result<ActionStream, ShellError> { let args = args.evaluate_once()?; let should_show_count = args.has_flag("count"); let input = args.input; let uniq_values = { let mut counter = IndexMap::<nu_protocol::Value, usize>::new(); for line in input.into_vec() { *counter.entry(line).or_insert(0) += 1; } counter }; let mut values_vec_deque = VecDeque::new(); if should_show_count { for item in uniq_values { use nu_protocol::Value; let value = { match item.0.value { UntaggedValue::Row(mut row) => { row.entries.insert( "count".to_string(), UntaggedValue::int(item.1).into_untagged_value(), ); Value { value: UntaggedValue::Row(row), tag: item.0.tag, } } UntaggedValue::Primitive(p) => { let mut map = IndexMap::<String, Value>::new(); map.insert( "value".to_string(), UntaggedValue::Primitive(p).into_untagged_value(), ); map.insert( "count".to_string(), UntaggedValue::int(item.1).into_untagged_value(), ); Value { value: UntaggedValue::row(map), tag: item.0.tag, } } UntaggedValue::Table(_) => { return Err(ShellError::labeled_error( "uniq -c cannot operate on tables.", "source", item.0.tag.span, )) } UntaggedValue::Error(_) | UntaggedValue::Block(_) => item.0, } }; values_vec_deque.push_back(value); } } else { for item in uniq_values { values_vec_deque.push_back(item.0); } } Ok(values_vec_deque.into_iter().to_action_stream()) } #[cfg(test)] mod tests { use super::ShellError; use super::Uniq; #[test] fn examples_work_as_expected() -> Result<(), ShellError> { use crate::examples::test as test_examples; test_examples(Uniq {}) } }