nu_command/matrix/
set_row.rs1use crate::matrix::MatrixValue;
2use crate::matrix::value::values_to_f64s;
3use nu_engine::command_prelude::*;
4
5#[derive(Clone)]
6pub struct MatrixSetRow;
7
8impl Command for MatrixSetRow {
9 fn name(&self) -> &str {
10 "matrix set-row"
11 }
12
13 fn signature(&self) -> Signature {
14 Signature::build("matrix set-row")
15 .input_output_types(vec![(
16 Type::Custom("matrix".into()),
17 Type::Custom("matrix".into()),
18 )])
19 .required(
20 "index",
21 SyntaxShape::Int,
22 "The row index to replace (0-based).",
23 )
24 .required(
25 "replacement",
26 SyntaxShape::List(Box::new(SyntaxShape::Number)),
27 "The new row values as a list of numbers.",
28 )
29 .category(Category::Filters)
30 }
31
32 fn description(&self) -> &str {
33 "Replace a row in a matrix."
34 }
35
36 fn search_terms(&self) -> Vec<&str> {
37 vec!["replace"]
38 }
39
40 fn run(
41 &self,
42 engine_state: &EngineState,
43 stack: &mut Stack,
44 call: &Call,
45 input: PipelineData,
46 ) -> Result<PipelineData, ShellError> {
47 let head = call.head;
48 let index: usize = call.req::<i64>(engine_state, stack, 0)? as usize;
49 let replacement: Value = call.req(engine_state, stack, 1)?;
50 let matrix = MatrixValue::from_value(&input.into_value(head)?)?;
51
52 let replacement_vals = match replacement {
53 Value::List { vals, .. } => vals,
54 _ => {
55 return Err(ShellError::Generic(
56 nu_protocol::shell_error::generic::GenericError::new(
57 "Invalid replacement",
58 "expected a list of numbers",
59 head,
60 ),
61 ));
62 }
63 };
64
65 let ncols = if matrix.array.ndim() >= 2 {
66 matrix.array.shape()[1]
67 } else {
68 1
69 };
70 if replacement_vals.len() != ncols {
71 return Err(ShellError::Generic(
72 nu_protocol::shell_error::generic::GenericError::new(
73 "Size mismatch",
74 format!(
75 "replacement has {} elements, but row has {} columns",
76 replacement_vals.len(),
77 ncols
78 ),
79 head,
80 ),
81 ));
82 }
83
84 if index >= matrix.array.shape()[0] {
85 return Err(ShellError::Generic(
86 nu_protocol::shell_error::generic::GenericError::new(
87 "Index out of bounds",
88 format!(
89 "row index {} is out of bounds, matrix has {} rows",
90 index,
91 matrix.array.shape()[0]
92 ),
93 head,
94 ),
95 ));
96 }
97
98 let floats = values_to_f64s(&replacement_vals, head)?;
99
100 let mut new_array = matrix.array;
101 for (j, &val) in floats.iter().enumerate() {
102 if new_array.ndim() == 1 {
103 new_array[[index]] = val;
104 } else {
105 new_array[[index, j]] = val;
106 }
107 }
108
109 Ok(MatrixValue::new(new_array)
110 .into_value(head)
111 .into_pipeline_data())
112 }
113
114 fn examples(&self) -> Vec<Example<'static>> {
115 vec![
116 Example {
117 description: "Replace the first row of a 2x3 matrix",
118 example: "matrix zeros 2 3 | matrix set-row 0 [1.0 2.0 3.0] | matrix into-nu | to nuon",
119 result: Some(Value::test_string("[[1.0, 2.0, 3.0], [0.0, 0.0, 0.0]]")),
120 },
121 Example {
122 description: "Replace the second row of a 2x2 matrix",
123 example: "matrix zeros 2 2 | matrix set-row 1 [4.0 5.0] | matrix into-nu | to nuon",
124 result: Some(Value::test_string("[[0.0, 0.0], [4.0, 5.0]]")),
125 },
126 ]
127 }
128}
129
130#[cfg(test)]
131mod test {
132 use super::*;
133
134 #[test]
135 fn test_examples() -> nu_test_support::Result {
136 nu_test_support::test().examples(MatrixSetRow)
137 }
138}