@@ -96,16 +96,44 @@ export class DataFrame {
9696
9797 // ─── construction ─────────────────────────────────────────────────────────
9898
99+ constructor ( columns : ReadonlyMap < string , Series < Scalar > > , index : Index < Label > ) ;
100+ constructor ( columns : Readonly < Record < string , Series < Scalar > > > , options ?: DataFrameOptions ) ;
99101 /**
100102 * Low-level constructor. Prefer the static factory methods for typical use.
101103 *
102- * @param columns - Ordered map of column name → Series (all same length and index).
103- * @param index - Row index (must match each Series' length).
104+ * @param columns - Ordered map of column name → Series (all same length and index),
105+ * or a plain record of column name → Series.
106+ * @param indexOrOptions - Row index for map input, or options for record input.
104107 */
105- constructor ( columns : ReadonlyMap < string , Series < Scalar > > , index : Index < Label > ) {
106- this . _columns = columns ;
107- this . index = index ;
108- this . columns = new Index < string > ( [ ...columns . keys ( ) ] ) ;
108+ constructor (
109+ columns : ReadonlyMap < string , Series < Scalar > > | Readonly < Record < string , Series < Scalar > > > ,
110+ indexOrOptions ?: Index < Label > | DataFrameOptions ,
111+ ) {
112+ if ( columns instanceof Map ) {
113+ if ( ! ( indexOrOptions instanceof Index ) ) {
114+ throw new TypeError ( "DataFrame constructor requires an Index when columns is a Map" ) ;
115+ }
116+ this . _columns = columns ;
117+ this . index = indexOrOptions ;
118+ this . columns = new Index < string > ( [ ...columns . keys ( ) ] ) ;
119+ return ;
120+ }
121+
122+ const entries = Object . entries ( columns ) ;
123+ const colMap = new Map < string , Series < Scalar > > ( ) ;
124+ for ( const [ name , series ] of entries ) {
125+ colMap . set ( name , series ) ;
126+ }
127+ const options = indexOrOptions instanceof Index ? { index : indexOrOptions } : indexOrOptions ;
128+ const firstSeries = entries [ 0 ] ?. [ 1 ] ;
129+ const inferredRows = firstSeries ?. size ?? 0 ;
130+ const rowIndex =
131+ options ?. index !== undefined
132+ ? resolveRowIndex ( inferredRows , options . index )
133+ : ( firstSeries ?. index ?? defaultRowIndex ( 0 ) ) ;
134+ this . _columns = options ?. index !== undefined ? reindexColumns ( colMap , rowIndex ) : colMap ;
135+ this . index = rowIndex ;
136+ this . columns = new Index < string > ( [ ...colMap . keys ( ) ] ) ;
109137 }
110138
111139 /**
@@ -254,6 +282,18 @@ export class DataFrame {
254282 return this . _columns . has ( name ) ;
255283 }
256284
285+ /** Alias for {@link has}. */
286+ hasColumn ( name : string ) : boolean {
287+ return this . has ( name ) ;
288+ }
289+
290+ /** Iterate `(columnName, Series)` pairs in column order. */
291+ * [ Symbol . iterator ] ( ) : IterableIterator < [ string , Series < Scalar > ] > {
292+ for ( const entry of this . _columns ) {
293+ yield entry ;
294+ }
295+ }
296+
257297 // ─── slicing ──────────────────────────────────────────────────────────────
258298
259299 /** Return the first `n` rows (default 5). */
@@ -848,7 +888,32 @@ function reindexColumns(
848888) : Map < string , Series < Scalar > > {
849889 const result = new Map < string , Series < Scalar > > ( ) ;
850890 for ( const [ name , series ] of colMap ) {
851- result . set ( name , new Series ( { data : series . values as Scalar [ ] , index : newIndex } ) ) ;
891+ if ( series . size === newIndex . size ) {
892+ result . set (
893+ name ,
894+ new Series ( {
895+ data : series . values ,
896+ index : newIndex ,
897+ dtype : series . dtype ,
898+ ...( series . name !== null ? { name : series . name } : { } ) ,
899+ } ) ,
900+ ) ;
901+ continue ;
902+ }
903+
904+ const resized : Scalar [ ] = new Array < Scalar > ( newIndex . size ) ;
905+ for ( let i = 0 ; i < newIndex . size ; i ++ ) {
906+ resized [ i ] = series . values [ i ] ?? null ;
907+ }
908+ result . set (
909+ name ,
910+ new Series ( {
911+ data : resized ,
912+ index : newIndex ,
913+ dtype : series . dtype ,
914+ ...( series . name !== null ? { name : series . name } : { } ) ,
915+ } ) ,
916+ ) ;
852917 }
853918 return result ;
854919}
0 commit comments