Skip to content

Sort step #71

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions docs/nodes/steps/algorithm.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- [qbrt](#qbrt)
- [root](#root)
- [round](#round)
- [sort](#sort)
- [sqrt](#sqrt)

These are steps that takes a single input (scalar / series / events /
Expand Down Expand Up @@ -792,6 +793,48 @@ given a certain precision:
* Precision `3`: `1234.567`


---

### `sort`

**Inputs**
>
> 1. `Scalar | Series | Event | Number`
>

**Output:** `Scalar | Series | Event | Number`

**Options**
>
> #### `order`
>
> **Type:** `String`
> **Required:** `False`
> **Allowed values:** `asc | desc`
> **Default value:** `asc`

>

**Shared options**
>
> <details><summary>Global options</summary>
>
> The following options are available globally on all steps.
>
> * [export](./index.md#export)
> * [output](./index.md#output)
> * [set](./index.md#set)
> * [space](./index.md#space)
>
>
></details>
>


Sorts the input in the specified order. By default, the values are sorted
in ascending order. The order can be changed by setting the `order`
property to `desc`.

---

### `sqrt`
Expand Down
3 changes: 1 addition & 2 deletions docs/nodes/steps/data-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
- [concatenate](#concatenate)
- [vector](#vector)

These are steps that uses events as inputs to affect the output
in various ways.
These are steps that create or manipulate data structures.


---
Expand Down
60 changes: 60 additions & 0 deletions src/lib/processing/algorithms/sort.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import test from 'ava';

import { f32, mockStep } from '../../../test-utils/mock-step';
import { Signal } from '../../models/signal';

import { SortStep } from './sort';

test('SortStep with invalid inputs', async(t) => {
await t.throwsAsync(mockStep(SortStep, [new Signal('hello')]).process());
await t.throwsAsync(mockStep(SortStep, [new Signal(undefined)]).process());
await t.throwsAsync(mockStep(SortStep, [undefined]).process());
await t.throwsAsync(mockStep(SortStep, []).process());
});

test('SortStep with invalid sort order', async(t) => {
await t.throws(() => mockStep(SortStep, [new Signal(-77)], { order: 'invalid' }));
});

test('SortStep with sort order in different case', async(t) => {
await t.notThrows(() => mockStep(SortStep, [new Signal(-77)], { order: 'ASC' }));
await t.notThrows(() => mockStep(SortStep, [new Signal(-77)], { order: 'DESC' }));
await t.notThrows(() => mockStep(SortStep, [new Signal(-77)], { order: 'Asc' }));
await t.notThrows(() => mockStep(SortStep, [new Signal(-77)], { order: 'Desc' }));
});

test('SortStep with single number', async(t) => {
const r1 = await mockStep(SortStep, [new Signal(-77)]).process();
t.is(r1.getValue(), -77);
const r2 = await mockStep(SortStep, [new Signal(77)]).process();
t.is(r2.getValue(), 77);


const r1b = await mockStep(SortStep, [new Signal(-77)], { order: 'asc' }).process();
t.is(r1b.getValue(), -77);
const r2b = await mockStep(SortStep, [new Signal(77)], { order: 'asc' }).process();
t.is(r2b.getValue(), 77);


const r1c = await mockStep(SortStep, [new Signal(-77)], { order: 'desc' }).process();
t.is(r1c.getValue(), -77);
const r2c = await mockStep(SortStep, [new Signal(77)], { order: 'desc' }).process();
t.is(r2c.getValue(), 77);
});

test('SortStep with random array', async(t) => {
const r1 = await mockStep(SortStep, [new Signal(f32(4, 2, 8, 55, 32))]).process();
t.deepEqual(r1.getValue(), f32(2, 4, 8, 32, 55));
const r2 = await mockStep(SortStep, [new Signal(f32(4, -2, 8, 55, -32))]).process();
t.deepEqual(r2.getValue(), f32(-32, -2, 4, 8, 55));

const r1b = await mockStep(SortStep, [new Signal(f32(4, 2, 8, 55, 32))], { order: 'asc' }).process();
t.deepEqual(r1b.getValue(), f32(2, 4, 8, 32, 55));
const r2b = await mockStep(SortStep, [new Signal(f32(4, -2, 8, 55, -32))], { order: 'asc' }).process();
t.deepEqual(r2b.getValue(), f32(-32, -2, 4, 8, 55));

const r1c = await mockStep(SortStep, [new Signal(f32(4, 2, 8, 55, 32))], { order: 'desc' }).process();
t.deepEqual(r1c.getValue(), f32(55, 32, 8, 4, 2));
const r2c = await mockStep(SortStep, [new Signal(f32(4, -2, 8, 55, -32))], { order: 'desc' }).process();
t.deepEqual(r2c.getValue(), f32(55, 8, 4, -2, -32));
});
53 changes: 53 additions & 0 deletions src/lib/processing/algorithms/sort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { PropertyType } from '../../models/property';
import { StepClass } from '../../step-registry';
import { ProcessingError } from '../../utils/processing-error';
import { markdownFmt } from '../../utils/template-literal-tags';

import { BaseAlgorithmStep } from './base-algorithm';

@StepClass({
name: 'sort',
category: 'Algorithm',
description: markdownFmt`
Sorts the input in the specified order. By default, the values are sorted
in ascending order. The order can be changed by setting the ''order''
property to ''desc''.
`,
inputs: [
{ type: ['Scalar', 'Series', 'Event', 'Number'] },
],
options: [{
name: 'order',
enum: ['asc', 'desc'],
type: 'String',
required: false,
default: 'asc',
}],
output: ['Scalar', 'Series', 'Event', 'Number'],
})
export class SortStep extends BaseAlgorithmStep {
order: 'asc' | 'desc';

function(a: TypedArray): TypedArray {
if (this.order === 'asc') {
return a.sort((a, b) => a - b);
}

return a.sort((a, b) => b - a);
}

init() {
super.init();

this.name = 'SortStep';

let order = this.getPropertyValue<string>('order', PropertyType.String, false) || 'asc';
order = order.toLowerCase();

if (order !== 'asc' && order !== 'desc') {
throw new ProcessingError(`Invalid order: ${order}`);
}

this.order = order as 'asc' | 'desc';
}
}
3 changes: 1 addition & 2 deletions src/lib/processing/concatenate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import { BaseStep } from './base-step';
@StepCategory({
name: 'Data structure',
description: markdownFmt`
These are steps that uses events as inputs to affect the output
in various ways.
These are steps that create or manipulate data structures.
`,
})
@StepClass({
Expand Down
1 change: 1 addition & 0 deletions src/lib/processing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export * from './algorithms/negate';
export * from './algorithms/power';
export * from './algorithms/root';
export * from './algorithms/round';
export * from './algorithms/sort';
export * from './algorithms/trigonometry';
export * from './algorithms/integral';
export * from './dot-product';
Expand Down