Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
manipulating_tables_and_lookup_tables [2026/08/07 03:03]
hermann old revision restored (2026/08/03 10:35)
manipulating_tables_and_lookup_tables [2026/08/18 03:09] (current)
hermann [Printing a table with any number of key columns]
Line 585: Line 585:
     }};     }};
 }}; }};
- 
-// priceTable is usable here, once the Group it was produced inside -- and 
-// through its sequenceInput,​ the loop that Group was forced to wait for -- 
-// has finished. 
 </​code>​ </​code>​
 +
 +''​priceTable''​ is usable here, once the Group it was produced inside — and through its ''​sequenceInput'',​ the loop that Group was forced to wait for — has finished.
  
 The loop's own iterations are still eligible to run in parallel with each other: nothing inside it is a Mux, nothing inside it is consumed from outside it, and it feeds no submodel output port -- see [[basic_data_flow|Basic Data Flow]]. Only the loop as a whole is sequenced against the merge, which is why this avoids the cost the Mux-accumulator pattern above pays on every single iteration. The loop's own iterations are still eligible to run in parallel with each other: nothing inside it is a Mux, nothing inside it is consumed from outside it, and it feeds no submodel output port -- see [[basic_data_flow|Basic Data Flow]]. Only the loop as a whole is sequenced against the merge, which is why this avoids the cost the Mux-accumulator pattern above pays on every single iteration.
Line 602: Line 600:
 [[Get Table Row]], [[Get Tuple Size]], and [[Get Tuple Value]] make the column-count side of this possible: a row read as a Tuple can be measured with ''​GetTupleSize'',​ and each of its elements retrieved by position, rather than by column name, with ''​GetTupleValue''​. Each retrieved element has type ''​TableValue''​ — a generic type able to hold either a Real or a String. [[Get Table Row]], [[Get Tuple Size]], and [[Get Tuple Value]] make the column-count side of this possible: a row read as a Tuple can be measured with ''​GetTupleSize'',​ and each of its elements retrieved by position, rather than by column name, with ''​GetTupleValue''​. Each retrieved element has type ''​TableValue''​ — a generic type able to hold either a Real or a String.
  
-[[String]] and [[Real Value]] each convert a ''​TableValue''​ the same conditional way: the conversion only succeeds if the ''​TableValue''​ actually holds that type, and raises an error otherwise — converting an already-typed,​ known ''​RealValue''​ or String, by contrast, never fails. ​Attempting the String conversion wrapped ​in [[Skip On Error]] turns that failure into a type test: ''​SkipOnError''​ catches the error rather than aborting the model, ​and its ''​executionCompletedSucessfully''​ output reports whether ​the ''​TableValue'' ​really was String. [[If Then]] and [[If Not Then]] branch on that result and take the matching path. The first uses the converted String directly. The second has already ruled String outso it extracts a ''​RealValue'' ​instead — safe nowsince only Real remains possible — and converts //that// known value to a stringA [[String Junction]] then recombines ​the two branches into one resultsince only one of them ever actually runs.+[[String]] and [[Real Value]] each convert a ''​TableValue''​ the same conditional way: the conversion only succeeds if the ''​TableValue''​ actually holds that type, and raises an error otherwise — converting an already-typed,​ known ''​RealValue''​ or String, by contrast, never fails. ​Wrapping each attempt ​in its own [[Skip On Error]] turns that failure into "​produced nothing"​ instead of aborting the model, ​so only the attempt that actually matches ​the ''​TableValue''​'s real type ever produces ​display string; the other attempt simply fails silently and produces nothing[[String Junction]] then picks whichever one exists. 
 + 
 +> **Note:** A junction always tries its first port before its second — see [[ego_script#​carrying_and_selecting_values_across_iterations|Carrying and selecting values across iterations]] for this rule stated generallysince it applies identically to every Junction functor (''​String'', ​''​Table'',​ ''​Value'',​ ''​Lookup Table'',​ ''​Map'',​ ''​Categorical Map'',​ ''​Folder''​)It makes no practical difference here, though: ​the two attempts below are mutually exclusive by constructionso only one of ''​stringDisplay''/''​realDisplay''​ is ever available for the junction to pick regardless of port order.
  
 <​code>​ <​code>​
Line 628: Line 628:
             displayColumn := $ [ $columnIndex - 1 ];             displayColumn := $ [ $columnIndex - 1 ];
  
-            // Attempt to read the cell as a String; SkipOnError ​catches the +            // Try the cell as a String; SkipOnError ​leaves stringDisplay 
-            // failure ​if it'​s ​actually a Real, rather than aborting. +            // unproduced ​if cellValue is actually a Real, rather than 
-            ​attempt ​:= SkipOnError .yes {{ +            // aborting ​the model
-                ​asString ​:= String cellValue+            ​:= SkipOnError .yes {{ 
-            }}; +                ​stringDisplay ​:= String cellValue;
- +
-            _ := IfThen attempt {{ +
-                stringDisplay := String asString;+
             }};             }};
  
-            ​_ := IfNotThen attempt {{ +            // Try the cell as a Real instead; ​SkipOnError leaves 
-                ​// cellValue was a Real instead; ​RealValue extracts it, and +            // realDisplay unproduced if cellValue is actually a String. 
-                // String ​— safe here, since converting a known Real never +            _ := SkipOnError ​.yes {{
-                // fails — turns it into a display string.+
                 asReal := RealValue cellValue;                 asReal := RealValue cellValue;
                 realDisplay := String asReal;                 realDisplay := String asReal;
             }};             }};
  
-            // Only one of stringDisplay/​realDisplay was actually produced+            // Exactly ​one of the two attempts above ever succeeds
-            // StringJunction picks whichever one has a value.+            // StringJunction picks whichever one was produced.
             cellDisplay := StringJunction stringDisplay realDisplay;​             cellDisplay := StringJunction stringDisplay realDisplay;​
  
Line 1049: Line 1045:
 ]; ];
  
-result := CalculatePythonExpression ​(String ​$"(+result := CalculatePythonExpression $"(
 inputTable = dinamica.inputs['​t1'​] inputTable = dinamica.inputs['​t1'​]
 header = inputTable[0] header = inputTable[0]
Line 1062: Line 1058:
  
 dinamica.outputs['​reshapedTable'​] = dinamica.prepareTable(newTable,​ 1) dinamica.outputs['​reshapedTable'​] = dinamica.prepareTable(newTable,​ 1)
-)"{{+)" {{
     NumberTable myTable 1;     NumberTable myTable 1;
 }}; }};
Line 1084: Line 1080:
  
             // Same generic Real/String printing technique as the earlier             // Same generic Real/String printing technique as the earlier
-            // example: ​attempt String first, SkipOnError ​catches the +            // example: ​try both conversions independentlyeach guarded by 
-            // failure if it'​s ​actually ​a Real, RealValue then converts it+            // its own SkipOnError, and let StringJunction pick whichever 
-            ​attempt ​:= SkipOnError .yes {{ +            // one was actually ​produced
-                ​asString ​:= String cellValue;+            ​:= SkipOnError .yes {{ 
 +                ​stringDisplay ​:= String cellValue;
             }};             }};
  
-            _ := IfThen attempt {{ +            _ := SkipOnError .yes {{
-                stringDisplay := String asString; +
-            }}; +
- +
-            _ := IfNotThen attempt ​{{+
                 asReal := RealValue cellValue;                 asReal := RealValue cellValue;
                 realDisplay := String asReal;                 realDisplay := String asReal;
Line 1120: Line 1113:
  
 Reach for a general Table instead when a single Real value per Real key isn't enough — when a row needs more than one associated value, or a String value, or a String key, or when rows need to be indexed by more than one key at once. A String key column costs more than the type change alone: iterating one means mapping each placeholder index back to its actual key inside the loop, so prefer a Real key column wherever the data allows. Reach for a general Table instead when a single Real value per Real key isn't enough — when a row needs more than one associated value, or a String value, or a String key, or when rows need to be indexed by more than one key at once. A String key column costs more than the type change alone: iterating one means mapping each placeholder index back to its actual key inside the loop, so prefer a Real key column wherever the data allows.
-