Skip to content

Commit fefcb31

Browse files
- add Locking ability to df.Prepend, Append, Insert, ClearRow, Remove, Update, UpdateRow, ReorderColumns, Names and NameToColumn etc
1 parent 0363953 commit fefcb31

File tree

9 files changed

+94
-102
lines changed

9 files changed

+94
-102
lines changed

dataframe.go

+73-81
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ func (df *DataFrame) NRows(options ...Options) int {
5757
}
5858

5959
return df.n
60-
6160
}
6261

6362
// SeriesReturnOpt is used to control if Row/Values method returns
@@ -187,56 +186,21 @@ func (df *DataFrame) ValuesIterator(options ...ValuesOptions) func(retOpt ...Ser
187186
}
188187

189188
// Prepend inserts a row at the beginning.
190-
func (df *DataFrame) Prepend(vals ...interface{}) {
191-
df.lock.Lock()
192-
defer df.lock.Unlock()
193-
194-
if len(vals) > 0 {
195-
196-
switch v := vals[0].(type) {
197-
case map[string]interface{}:
198-
199-
names := map[string]struct{}{}
200-
for name := range v {
201-
names[name] = struct{}{}
202-
}
203-
204-
// Check if number of vals is equal to number of series
205-
if len(names) != len(df.Series) {
206-
panic("no. of args not equal to no. of series")
207-
}
208-
209-
for name, val := range v {
210-
col, err := df.NameToColumn(name)
211-
if err != nil {
212-
panic(err)
213-
}
214-
df.Series[col].Prepend(val)
215-
}
216-
default:
217-
// Check if number of vals is equal to number of series
218-
if len(vals) != len(df.Series) {
219-
panic("no. of args not equal to no. of series")
220-
}
221-
222-
for idx, val := range vals {
223-
df.Series[idx].Prepend(val)
224-
}
225-
}
226-
227-
df.n++
228-
}
189+
func (df *DataFrame) Prepend(opts *Options, vals ...interface{}) {
190+
df.Insert(0, opts, vals...)
229191
}
230192

231193
// Append inserts a row at the end.
232-
func (df *DataFrame) Append(vals ...interface{}) {
233-
df.Insert(df.n, vals...)
194+
func (df *DataFrame) Append(opts *Options, vals ...interface{}) {
195+
df.Insert(df.n, opts, vals...)
234196
}
235197

236198
// Insert adds a row to a particular position.
237-
func (df *DataFrame) Insert(row int, vals ...interface{}) {
238-
df.lock.Lock()
239-
defer df.lock.Unlock()
199+
func (df *DataFrame) Insert(row int, opts *Options, vals ...interface{}) {
200+
if opts == nil || !opts.DontLock {
201+
df.lock.Lock()
202+
defer df.lock.Unlock()
203+
}
240204

241205
df.insert(row, vals...)
242206
}
@@ -248,26 +212,35 @@ func (df *DataFrame) insert(row int, vals ...interface{}) {
248212
switch v := vals[0].(type) {
249213
case map[string]interface{}:
250214

251-
names := map[string]struct{}{}
252-
for name := range v {
253-
names[name] = struct{}{}
254-
}
255-
256215
// Check if number of vals is equal to number of series
257-
if len(names) != len(df.Series) {
216+
if len(v) != len(df.Series) {
258217
panic("no. of args not equal to no. of series")
259218
}
260219

261220
for name, val := range v {
262-
col, err := df.NameToColumn(name)
221+
col, err := df.NameToColumn(name, dontLock)
263222
if err != nil {
264223
panic(err)
265224
}
266225
df.Series[col].Insert(row, val)
267226
}
268227
case map[interface{}]interface{}:
269228

270-
if len(v) != len(df.Series) {
229+
// Check if number of vals is equal to number of series
230+
names := map[string]struct{}{}
231+
232+
for key := range v {
233+
switch kTyp := key.(type) {
234+
case int:
235+
names[df.Series[kTyp].Name(dontLock)] = struct{}{}
236+
case string:
237+
names[kTyp] = struct{}{}
238+
default:
239+
panic("unknown type in insert argument. Must be an int or string.")
240+
}
241+
}
242+
243+
if len(names) != len(df.Series) {
271244
panic("no. of args not equal to no. of series")
272245
}
273246

@@ -276,7 +249,7 @@ func (df *DataFrame) insert(row int, vals ...interface{}) {
276249
case int:
277250
df.Series[CTyp].Insert(row, val)
278251
case string:
279-
col, err := df.NameToColumn(CTyp)
252+
col, err := df.NameToColumn(CTyp, dontLock)
280253
if err != nil {
281254
panic(err)
282255
}
@@ -301,19 +274,23 @@ func (df *DataFrame) insert(row int, vals ...interface{}) {
301274
}
302275

303276
// ClearRow makes an entire row nil.
304-
func (df *DataFrame) ClearRow(row int) {
305-
df.lock.Lock()
306-
defer df.lock.Unlock()
277+
func (df *DataFrame) ClearRow(row int, opts ...Options) {
278+
if len(opts) == 0 || (len(opts) > 0 && !opts[0].DontLock) {
279+
df.lock.Lock()
280+
defer df.lock.Unlock()
281+
}
307282

308283
for i := range df.Series {
309284
df.Series[i].Update(row, nil, dontLock) //???
310285
}
311286
}
312287

313288
// Remove deletes a row.
314-
func (df *DataFrame) Remove(row int) {
315-
df.lock.Lock()
316-
defer df.lock.Unlock()
289+
func (df *DataFrame) Remove(row int, opts ...Options) {
290+
if len(opts) == 0 || (len(opts) > 0 && !opts[0].DontLock) {
291+
df.lock.Lock()
292+
defer df.lock.Unlock()
293+
}
317294

318295
for i := range df.Series {
319296
df.Series[i].Remove(row)
@@ -323,15 +300,15 @@ func (df *DataFrame) Remove(row int) {
323300

324301
// Update is used to update a specific entry.
325302
// col can be the name of the series or the column number.
326-
func (df *DataFrame) Update(row int, col interface{}, val interface{}, options ...Options) {
327-
if len(options) == 0 || (len(options) > 0 && !options[0].DontLock) {
303+
func (df *DataFrame) Update(row int, col interface{}, val interface{}, opts ...Options) {
304+
if len(opts) == 0 || (len(opts) > 0 && !opts[0].DontLock) {
328305
df.lock.Lock()
329306
defer df.lock.Unlock()
330307
}
331308

332309
switch name := col.(type) {
333310
case string:
334-
_col, err := df.NameToColumn(name)
311+
_col, err := df.NameToColumn(name, dontLock)
335312
if err != nil {
336313
panic(err)
337314
}
@@ -342,16 +319,18 @@ func (df *DataFrame) Update(row int, col interface{}, val interface{}, options .
342319
}
343320

344321
// UpdateRow will update an entire row.
345-
func (df *DataFrame) UpdateRow(row int, vals ...interface{}) {
346-
df.lock.Lock()
347-
defer df.lock.Unlock()
322+
func (df *DataFrame) UpdateRow(row int, opts *Options, vals ...interface{}) {
323+
if opts == nil || !opts.DontLock {
324+
df.lock.Lock()
325+
defer df.lock.Unlock()
326+
}
348327

349328
if len(vals) > 0 {
350329

351330
switch v := vals[0].(type) {
352331
case map[string]interface{}:
353332
for name, val := range v {
354-
col, err := df.NameToColumn(name)
333+
col, err := df.NameToColumn(name, dontLock)
355334
if err != nil {
356335
panic(err)
357336
}
@@ -363,7 +342,7 @@ func (df *DataFrame) UpdateRow(row int, vals ...interface{}) {
363342
case int:
364343
df.Series[CTyp].Update(row, val)
365344
case string:
366-
col, err := df.NameToColumn(CTyp)
345+
col, err := df.NameToColumn(CTyp, dontLock)
367346
if err != nil {
368347
panic(err)
369348
}
@@ -386,9 +365,13 @@ func (df *DataFrame) UpdateRow(row int, vals ...interface{}) {
386365
}
387366

388367
// Names will return a list of all the series names.
389-
func (df *DataFrame) Names() []string {
390-
names := []string{}
368+
func (df *DataFrame) Names(opts ...Options) []string {
369+
if len(opts) == 0 || (len(opts) > 0 && !opts[0].DontLock) {
370+
df.lock.RLock()
371+
defer df.lock.RUnlock()
372+
}
391373

374+
names := []string{}
392375
for _, aSeries := range df.Series {
393376
names = append(names, aSeries.Name())
394377
}
@@ -398,7 +381,12 @@ func (df *DataFrame) Names() []string {
398381

399382
// NameToColumn returns the index of the series based on the name.
400383
// The starting index is 0.
401-
func (df *DataFrame) NameToColumn(seriesName string) (int, error) {
384+
func (df *DataFrame) NameToColumn(seriesName string, opts ...Options) (int, error) {
385+
if len(opts) == 0 || (len(opts) > 0 && !opts[0].DontLock) {
386+
df.lock.RLock()
387+
defer df.lock.RUnlock()
388+
}
389+
402390
for idx, aSeries := range df.Series {
403391
if aSeries.Name() == seriesName {
404392
return idx, nil
@@ -411,9 +399,11 @@ func (df *DataFrame) NameToColumn(seriesName string) (int, error) {
411399
// ReorderColumns reorders the columns based on an ordered list of
412400
// column names. The length of newOrder must match the number of columns
413401
// in the Dataframe. The column names in newOrder must be unique.
414-
func (df *DataFrame) ReorderColumns(newOrder []string) error {
415-
df.lock.Lock()
416-
defer df.lock.Unlock()
402+
func (df *DataFrame) ReorderColumns(newOrder []string, opts ...Options) error {
403+
if len(opts) == 0 || (len(opts) > 0 && !opts[0].DontLock) {
404+
df.lock.Lock()
405+
defer df.lock.Unlock()
406+
}
417407

418408
if len(newOrder) != len(df.Series) {
419409
return errors.New("length of newOrder must match number of columns")
@@ -432,7 +422,7 @@ func (df *DataFrame) ReorderColumns(newOrder []string) error {
432422
series := []Series{}
433423

434424
for _, v := range newOrder {
435-
idx, err := df.NameToColumn(v)
425+
idx, err := df.NameToColumn(v, dontLock)
436426
if err != nil {
437427
return errors.New(err.Error() + ": " + v)
438428
}
@@ -446,11 +436,13 @@ func (df *DataFrame) ReorderColumns(newOrder []string) error {
446436
}
447437

448438
// RemoveSeries will remove a Series from the Dataframe.
449-
func (df *DataFrame) RemoveSeries(seriesName string) error {
450-
df.lock.Lock()
451-
defer df.lock.Unlock()
439+
func (df *DataFrame) RemoveSeries(seriesName string, opts ...Options) error {
440+
if len(opts) == 0 || (len(opts) > 0 && !opts[0].DontLock) {
441+
df.lock.Lock()
442+
defer df.lock.Unlock()
443+
}
452444

453-
idx, err := df.NameToColumn(seriesName)
445+
idx, err := df.NameToColumn(seriesName, dontLock)
454446
if err != nil {
455447
return errors.New(err.Error() + ": " + seriesName)
456448
}
@@ -460,8 +452,8 @@ func (df *DataFrame) RemoveSeries(seriesName string) error {
460452
}
461453

462454
// Swap is used to swap 2 values based on their row position.
463-
func (df *DataFrame) Swap(row1, row2 int, options ...Options) {
464-
if len(options) == 0 || (len(options) > 0 && !options[0].DontLock) {
455+
func (df *DataFrame) Swap(row1, row2 int, opts ...Options) {
456+
if len(opts) == 0 || (len(opts) > 0 && !opts[0].DontLock) {
465457
df.lock.Lock()
466458
defer df.lock.Unlock()
467459
}

dataframe_test.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,22 @@ func TestInsertAndRemove(t *testing.T) {
3131
s2 := NewSeriesFloat64("sales", nil, 50.3, 23.4, 56.2)
3232
df := NewDataFrame(s1, s2)
3333

34-
df.Append(9, 123.6)
34+
df.Append(&dontLock, 9, 123.6)
3535

36-
df.Append(map[string]interface{}{
36+
df.Append(&dontLock, map[string]interface{}{
3737
"day": 10,
3838
"sales": nil,
3939
})
4040

4141
df.Remove(0)
4242

43-
df.Prepend(map[string]interface{}{
43+
df.Prepend(&dontLock, map[string]interface{}{
4444
"day": 99,
4545
"sales": 199.99,
4646
})
4747

48-
df.Prepend(1000, 10000)
49-
df.UpdateRow(0, 10000, 1000)
48+
df.Prepend(&dontLock, 1000, 10000)
49+
df.UpdateRow(0, &dontLock, 10000, 1000)
5050
df.Update(0, 1, 9000)
5151

5252
expected := `+-----+-------+---------+
@@ -191,7 +191,7 @@ func TestSort(t *testing.T) {
191191
for key, val := range vals {
192192
switch colName := key.(type) {
193193
case string:
194-
idx, _ := df.NameToColumn(colName)
194+
idx, _ := df.NameToColumn(colName, dontLock)
195195

196196
expected := expectedValues[idx][*row]
197197
actual := val //df.Series[idx].Value(*row)

exports/excel.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func ExportToExcel(ctx context.Context, outputFilePath string, df *dataframe.Dat
6262
// Add first row to excel sheet for header fields
6363
sheetRow = sheet.AddRow()
6464
// Write Header fields first
65-
for _, field := range df.Names() {
65+
for _, field := range df.Names(dataframe.DontLock) {
6666
cell = sheetRow.AddCell() // set column cell
6767
cell.Value = field // assign field to cell
6868
}

exports/sql.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func ExportToSQL(ctx context.Context, db execContexter, df *dataframe.DataFrame,
177177
columnNames = append(columnNames, pk.PrimaryKey)
178178
}
179179

180-
for _, seriesName := range df.Names() {
180+
for _, seriesName := range df.Names(dataframe.DontLock) {
181181

182182
colName, exists := seriesToColumn[seriesName]
183183
if exists && colName == nil {

imports/csv.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ func LoadFromCSV(ctx context.Context, r io.ReadSeeker, options ...CSVLoadOptions
171171

172172
if len(options) > 0 && len(options[0].DictateDataType) > 0 {
173173

174-
name := df.Names()[idx]
174+
name := df.Names(dataframe.DontLock)[idx]
175175

176176
// Check if a datatype is dictated
177177
typ, exists := options[0].DictateDataType[name]
@@ -236,9 +236,9 @@ func LoadFromCSV(ctx context.Context, r io.ReadSeeker, options ...CSVLoadOptions
236236
}
237237

238238
if init == nil {
239-
df.Append(insertVals...)
239+
df.Append(&dataframe.DontLock, insertVals...)
240240
} else {
241-
df.UpdateRow(row-1, insertVals...)
241+
df.UpdateRow(row-1, &dataframe.DontLock, insertVals...)
242242
}
243243

244244
}

imports/jsonl.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,9 @@ func LoadFromJSON(ctx context.Context, r io.ReadSeeker, options ...JSONLoadOptio
198198
}
199199

200200
if init == nil {
201-
df.Append(make([]interface{}, len(df.Series))...)
201+
df.Append(&dataframe.DontLock, make([]interface{}, len(df.Series))...)
202202
}
203-
df.UpdateRow(row-1, insertVals)
203+
df.UpdateRow(row-1, &dataframe.DontLock, insertVals)
204204

205205
} else {
206206

@@ -262,9 +262,9 @@ func LoadFromJSON(ctx context.Context, r io.ReadSeeker, options ...JSONLoadOptio
262262
}
263263

264264
if init == nil {
265-
df.Append(make([]interface{}, len(df.Series))...)
265+
df.Append(&dataframe.DontLock, make([]interface{}, len(df.Series))...)
266266
}
267-
df.UpdateRow(row-1, insertVals)
267+
df.UpdateRow(row-1, &dataframe.DontLock, insertVals)
268268

269269
}
270270
}
@@ -274,7 +274,7 @@ func LoadFromJSON(ctx context.Context, r io.ReadSeeker, options ...JSONLoadOptio
274274
}
275275

276276
// The order is not stable
277-
names := df.Names()
277+
names := df.Names(dataframe.DontLock)
278278
sort.Strings(names)
279279
df.ReorderColumns(names)
280280

0 commit comments

Comments
 (0)