Skip to content

Commit f64b62d

Browse files
authored
Merge pull request #28 from AlphaQuantJS/dev
feat: implement DataFrame filtering and indexing methods with tests
2 parents c8e35fd + f5af8b8 commit f64b62d

25 files changed

Lines changed: 1956 additions & 157 deletions

File tree

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* DataFrame display methods
3+
*
4+
* This module exports all display methods for DataFrame.
5+
* Methods are registered using extendDataFrame.
6+
*
7+
* @module methods/dataframe/display
8+
*/
9+
10+
import { DataFrame } from '../../../data/model/index.js';
11+
import { extendDataFrame } from '../../../data/model/extendDataFrame.js';
12+
import * as pool from './pool.js';
13+
14+
extendDataFrame(DataFrame.prototype, pool); // without namespace — base display methods
15+
16+
// export directly (so that you can call display(df) if needed)
17+
export * from './pool.js';

packages/core/src/methods/dataframe/filtering/expr$.js

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,46 +47,52 @@ export function expr$(df, strings, ...values) {
4747
if (filteredRows.length === 0) {
4848
// Create a new DataFrame instance with the same options as the original
4949
const result = new df.constructor({}, df._options);
50-
50+
5151
// For each column, create a Series with the appropriate type
5252
for (const col of allColumns) {
5353
// Get the original column data to determine its type
5454
const originalColumn = df._columns[col];
5555
const originalArray = originalColumn.vector.__data;
56-
56+
5757
// Create an empty array with the same type
58-
if (ArrayBuffer.isView(originalArray) && !(originalArray instanceof DataView)) {
58+
if (
59+
ArrayBuffer.isView(originalArray) &&
60+
!(originalArray instanceof DataView)
61+
) {
5962
const TypedArrayConstructor = originalArray.constructor;
6063
const emptyTypedArray = new TypedArrayConstructor(0);
6164
result._columns[col] = createTypedSeries(emptyTypedArray, col, df);
6265
} else {
6366
result._columns[col] = createTypedSeries([], col, df);
6467
}
65-
68+
6669
// Add to column order
6770
if (!result._order.includes(col)) {
6871
result._order.push(col);
6972
}
7073
}
71-
74+
7275
return result;
7376
}
7477

7578
// For non-empty results, create a new DataFrame with filtered rows
7679
// Create a new DataFrame instance with the same options as the original
7780
const result = new df.constructor({}, df._options);
78-
81+
7982
// For each column, create a Series with the appropriate type
8083
for (const col of allColumns) {
8184
// Get the original column data to determine its type
8285
const originalColumn = df._columns[col];
8386
const originalArray = originalColumn.vector.__data;
84-
87+
8588
// Extract values for this column from the filtered rows
86-
const values = filteredRows.map(row => row[col]);
87-
89+
const values = filteredRows.map((row) => row[col]);
90+
8891
// Preserve the array type if it's a typed array
89-
if (ArrayBuffer.isView(originalArray) && !(originalArray instanceof DataView)) {
92+
if (
93+
ArrayBuffer.isView(originalArray) &&
94+
!(originalArray instanceof DataView)
95+
) {
9096
const TypedArrayConstructor = originalArray.constructor;
9197
const typedValues = new TypedArrayConstructor(values.length);
9298
values.forEach((value, i) => {
@@ -96,19 +102,19 @@ export function expr$(df, strings, ...values) {
96102
} else {
97103
result._columns[col] = createTypedSeries(values, col, df);
98104
}
99-
105+
100106
// Add to column order
101107
if (!result._order.includes(col)) {
102108
result._order.push(col);
103109
}
104110
}
105-
111+
106112
return result;
107113
}
108114

109115
/**
110116
* Create a predicate function for filtering rows
111-
*
117+
*
112118
* @param {string} expr - Expression to evaluate
113119
* @returns {Function} - Predicate function
114120
* @private
@@ -134,4 +140,3 @@ function createPredicate(expr) {
134140
}
135141

136142
// Export the expr$ method directly
137-
export { expr$ };

packages/core/src/methods/dataframe/filtering/filter.js

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,44 +31,50 @@ export function filter(df, predicate) {
3131
if (filteredRows.length === 0) {
3232
// Create a new DataFrame instance with the same options as the original
3333
const result = new df.constructor({}, df._options);
34-
34+
3535
// For each column, create a Series with the appropriate type
3636
for (const col of allColumns) {
3737
// Get the original column data to determine its type
3838
const originalColumn = df._columns[col];
3939
const originalArray = originalColumn.vector.__data;
40-
40+
4141
// Create an empty array with the same type
42-
if (ArrayBuffer.isView(originalArray) && !(originalArray instanceof DataView)) {
42+
if (
43+
ArrayBuffer.isView(originalArray) &&
44+
!(originalArray instanceof DataView)
45+
) {
4346
const TypedArrayConstructor = originalArray.constructor;
4447
const emptyTypedArray = new TypedArrayConstructor(0);
4548
result._columns[col] = createTypedSeries(emptyTypedArray, col, df);
4649
} else {
4750
result._columns[col] = createTypedSeries([], col, df);
4851
}
49-
52+
5053
// Add to column order
5154
if (!result._order.includes(col)) {
5255
result._order.push(col);
5356
}
5457
}
55-
58+
5659
return result;
5760
}
5861

5962
// For non-empty results, create a new DataFrame with filtered rows
6063
// Create a new DataFrame instance with the same options as the original
6164
const result = new df.constructor({}, df._options);
62-
65+
6366
// For each column, create a Series with the appropriate type
6467
for (const col of allColumns) {
6568
// Get the original column data to determine its type
6669
const originalColumn = df._columns[col];
6770
const originalArray = originalColumn.vector.__data;
68-
const values = filteredRows.map(row => row[col]);
69-
71+
const values = filteredRows.map((row) => row[col]);
72+
7073
// Preserve the array type if it's a typed array
71-
if (ArrayBuffer.isView(originalArray) && !(originalArray instanceof DataView)) {
74+
if (
75+
ArrayBuffer.isView(originalArray) &&
76+
!(originalArray instanceof DataView)
77+
) {
7278
const TypedArrayConstructor = originalArray.constructor;
7379
const typedValues = new TypedArrayConstructor(values.length);
7480
values.forEach((value, i) => {
@@ -78,15 +84,14 @@ export function filter(df, predicate) {
7884
} else {
7985
result._columns[col] = createTypedSeries(values, col, df);
8086
}
81-
87+
8288
// Add to column order
8389
if (!result._order.includes(col)) {
8490
result._order.push(col);
8591
}
8692
}
87-
93+
8894
return result;
8995
}
9096

9197
// Export the filter method directly
92-
export { filter };

packages/core/src/methods/dataframe/filtering/iloc.js

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/*-------------------------------------------------------------------------*
22
| DataFrame -› filtering · iloc() |
33
| |
4-
| Выбор строк и колонок из DataFrame по целочисленным позициям. |
4+
| Selection of rows and columns from DataFrame by integer positions. |
55
| |
6-
| df.iloc(5) → выбор строки с индексом 5 |
7-
| df.iloc([1, 3, 5]) → выбор строк с указанными индексами |
8-
| df.iloc(5, 2) → выбор значения в строке 5, колонке 2 |
9-
| df.iloc([1, 3], [0, 2]) → выбор строк 1,3 и колонок 0,2 |
6+
| df.iloc(5) → select row with index 5 |
7+
| df.iloc([1, 3, 5]) → select rows with specified indices |
8+
| df.iloc(5, 2) → select value in row 5, column 2 |
9+
| df.iloc([1, 3], [0, 2]) → select rows 1,3 and columns 0,2 |
1010
*-------------------------------------------------------------------------*/
1111

1212
/**
@@ -75,7 +75,10 @@ export function iloc(df, rowSelector = null, colSelector = null) {
7575
// Process column selector
7676
if (colSelector === null || colSelector === undefined) {
7777
// If selector is null, select all columns
78-
selectedColumnIndices = Array.from({ length: allColumns.length }, (_, i) => i);
78+
selectedColumnIndices = Array.from(
79+
{ length: allColumns.length },
80+
(_, i) => i,
81+
);
7982
} else if (typeof colSelector === 'number') {
8083
// Single column index
8184
const idx = colSelector < 0 ? allColumns.length + colSelector : colSelector;
@@ -118,16 +121,19 @@ export function iloc(df, rowSelector = null, colSelector = null) {
118121

119122
// Create a new DataFrame instance with the same options as the original
120123
const result = new df.constructor({}, df._options);
121-
124+
122125
// For each selected column, create a Series with the appropriate type
123126
for (const col of selectedColumns) {
124127
// Get the original column data to determine its type
125128
const originalColumn = df._columns[col];
126129
const originalArray = originalColumn.vector.__data;
127-
const values = selectedIndices.map(index => rows[index][col]);
128-
130+
const values = selectedIndices.map((index) => rows[index][col]);
131+
129132
// Preserve the array type if it's a typed array
130-
if (ArrayBuffer.isView(originalArray) && !(originalArray instanceof DataView)) {
133+
if (
134+
ArrayBuffer.isView(originalArray) &&
135+
!(originalArray instanceof DataView)
136+
) {
131137
const TypedArrayConstructor = originalArray.constructor;
132138
const typedValues = new TypedArrayConstructor(values.length);
133139
values.forEach((value, i) => {
@@ -137,15 +143,14 @@ export function iloc(df, rowSelector = null, colSelector = null) {
137143
} else {
138144
result._columns[col] = createTypedSeries(values, col, df);
139145
}
140-
146+
141147
// Add to column order
142148
if (!result._order.includes(col)) {
143149
result._order.push(col);
144150
}
145151
}
146-
152+
147153
return result;
148154
}
149155

150156
// Export the method for the pool
151-
export default { iloc };

0 commit comments

Comments
 (0)