When processing streaming data with complex nested structures like array vectors in DolphinDB's Reactive State Engine, manipulating elements within individual rows is a common requirement. A frequent question developers ask is: Can we reverse row contents using syntax like reverse(H:col), and what does the H: prefix signify?

In this guide, we clarify the misconception around H:, explain why reverse() behaves differently, and show the exact, idiomatic approach to reversing array vectors row by row in DolphinDB.

Does reverse(H:arrCol) Work?

Short answer: No. reverse(H:arrCol) is not valid syntax in DolphinDB.

If you attempt to use H:arrCol inside createReactiveStateEngine, DolphinDB will throw a syntax error. The H: prefix does not exist as a keyword or modifier in DolphinDB. It often stems from confusion with other array-oriented languages (such as kdb+/q) or a mistaken belief that H: stands for "horizontal" vector manipulation.

Why Standard reverse() Doesn't Work Row-Wise

In DolphinDB, reverse() is designed to operate vertically (across historical rows in a column or on standard 1D vectors). When applied to an array vector:

  • reverse() expects to reverse the temporal order of rows (i.e., flipping record order across time windows), not the elements inside a specific row's array.
  • Inside a streaming engine where calculations are evaluated incrementally per incoming record, applying a temporal reverse() without a defined rolling window causes type or state mismatch errors.

The Correct Solution: Use rowReverse()

To manipulate elements within each row of an array vector (horizontal processing), DolphinDB provides a dedicated family of row* functions. To invert the order of elements within each array (e.g., transforming [1, 2, 3] into [3, 2, 1]), use rowReverse.

Working Code Example

Here is a complete, minimal reproducible example demonstrating how to set up the Reactive State Engine with rowReverse:

// 1. Clean up any existing engine with the same name
try { dropStreamEngine("reverseEngine") } catch(ex) {}

// 2. Define schema for input stream and output table
share streamTable(1:0, `time`sym`arrCol, [TIMESTAMP, SYMBOL, INT[]]) as inputStream
output = table(100:0, `time`sym`reversed, [TIMESTAMP, SYMBOL, INT[]])

// 3. Create the Reactive State Engine using rowReverse
engine = createReactiveStateEngine(
    name="reverseEngine",
    metrics=<[rowReverse(arrCol) as reversed]>,
    dummyTable=inputStream,
    outputTable=output,
    timeColumn=`time,
    keyColumn=`sym
)

// 4. Subscribe the engine to the stream table
subscribeTable(tableName="inputStream", actionName="reverseSub", offset=0, handler=append!{engine}, msgAsTable=true)

// 5. Test with sample data
t = table(take(2023.10.01T09:30:00.000 + 1000 * (1..2), 2) as time,
          `AAPL`MSFT as sym,
          [[1, 2, 3], [10, 20, 30, 40]] as arrCol)
inputStream.append!(t)

// 6. Verify results
select * from output

Output

time                    sym  reversed
----------------------- ---- ------------
2023.10.01T09:30:01.000 AAPL [3, 2, 1]
2023.10.01T09:30:02.000 MSFT [40, 30, 20, 10]

Key Takeaways for Array Vectors in Streaming Engines

  • Use row* functions for horizontal operations: For inner-array transformations, look for functions like rowReverse, rowSum, rowMin, rowMax, and rowAvg.
  • Memory efficiency: Array vectors in DolphinDB store nested vectors contiguously in memory per record, making row* functions significantly faster and more cache-friendly than applying higher-order looping functions like each.
  • Engine compatibility: rowReverse is stateless and fully optimized for reactive state engines, executing with zero added latency on incoming stream bars or ticks.