Skip to content
21 changes: 11 additions & 10 deletions dataframe.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func (df *DataFrame) NRows(options ...Options) int {

// ValuesOptions is used to modify the behaviour of Values().
type ValuesOptions struct {

// InitialRow represents the starting value for iterating.
InitialRow int

Expand Down Expand Up @@ -242,9 +243,11 @@ func (df *DataFrame) Remove(row int) {

// Update is used to update a specific entry.
// col can the name of the series or the column number.
func (df *DataFrame) Update(row int, col interface{}, val interface{}) {
df.lock.Lock()
defer df.lock.Unlock()
func (df *DataFrame) Update(row int, col interface{}, val interface{}, options ...Options) {
if len(options) == 0 || (len(options) > 0 && !options[0].DontLock) {
df.lock.Lock()
defer df.lock.Unlock()
}

switch name := col.(type) {
case string:
Expand Down Expand Up @@ -362,14 +365,12 @@ func (df *DataFrame) RemoveSeries(seriesName string) error {
}

// Swap is used to swap 2 values based on their row position.
func (df *DataFrame) Swap(row1, row2 int) {
df.lock.Lock()
defer df.lock.Unlock()

df.swap(row1, row2)
}
func (df *DataFrame) Swap(row1, row2 int, options ...Options) {
if len(options) == 0 || (len(options) > 0 && !options[0].DontLock) {
df.lock.Lock()
defer df.lock.Unlock()
}

func (df *DataFrame) swap(row1, row2 int) {
for idx := range df.Series {
df.Series[idx].Swap(row1, row2)
}
Expand Down
4 changes: 2 additions & 2 deletions exports/csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func ExportToCSV(ctx context.Context, w io.Writer, df *dataframe.DataFrame, opti
return err
}

nRows := df.NRows(dataframe.Options{DontLock: true})
nRows := df.NRows(dataframe.DontLock)

if nRows > 0 {

Expand Down Expand Up @@ -89,7 +89,7 @@ func ExportToCSV(ctx context.Context, w io.Writer, df *dataframe.DataFrame, opti
if val == nil {
sVals = append(sVals, nullString)
} else {
sVals = append(sVals, aSeries.ValueString(row, dataframe.Options{DontLock: true}))
sVals = append(sVals, aSeries.ValueString(row, dataframe.DontLock))
}
}

Expand Down
2 changes: 1 addition & 1 deletion exports/excel.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func ExportToExcel(ctx context.Context, outputFilePath string, df *dataframe.Dat
}
}

nRows := df.NRows(dataframe.Options{DontLock: true})
nRows := df.NRows(dataframe.DontLock)

if nRows > 0 {

Expand Down
2 changes: 1 addition & 1 deletion exports/json1.go → exports/jsonl.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func ExportToJSON(ctx context.Context, w io.Writer, df *dataframe.DataFrame, opt
}
}

nRows := df.NRows(dataframe.Options{DontLock: true})
nRows := df.NRows(dataframe.DontLock)

if nRows > 0 {

Expand Down
3 changes: 3 additions & 0 deletions helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ func BoolValueFormatter(v interface{}) string {
return ""
}
}

// DontLock is short-hand for various functions that permit disabling locking.
var DontLock = Options{DontLock: true}
1 change: 0 additions & 1 deletion imports/csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,5 +236,4 @@ func LoadFromCSV(ctx context.Context, r io.ReadSeeker, options ...CSVLoadOptions
}

return df, nil

}
3 changes: 1 addition & 2 deletions imports/jsonl.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,7 @@ func LoadFromJSON(ctx context.Context, r io.ReadSeeker, options ...JSONLoadOptio

if df == nil {
return nil, dataframe.ErrNoRows
} else {
return df, nil
}

return df, nil
}
2 changes: 1 addition & 1 deletion imports/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,6 @@ func LoadFromSQL(ctx context.Context, stmt *sql.Stmt, options *SQLLoadOptions, a
excess--
}
}
return df, nil

return df, nil
}
43 changes: 21 additions & 22 deletions range.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,34 @@ func (r *Range) NRows(length ...int) (int, error) {
}

return e - s + 1, nil
} else {
if r.End == nil {
return 0, errors.New("End is nil so length must be provided")
}
}

var s int
if r.End == nil {
return 0, errors.New("End is nil so length must be provided")
}

if r.Start != nil {
s = *r.Start
}
var s int

if s < 0 || *r.End < 0 {
return 0, errors.New("range invalid")
}
if r.Start != nil {
s = *r.Start
}

if *r.End < s {
return 0, errors.New("range invalid")
}
if s < 0 || *r.End < 0 {
return 0, errors.New("range invalid")
}

return *r.End - s + 1, nil
if *r.End < s {
return 0, errors.New("range invalid")
}

return *r.End - s + 1, nil
}

// Limits is used to return the start and end limits of a Range
// object for a given Dataframe or Series with len number of rows.
func (r *Range) Limits(len int) (s int, e int, _ error) {
// object for a given Dataframe or Series with length number of rows.
func (r *Range) Limits(length int) (s int, e int, _ error) {

if len <= 0 {
if length <= 0 {
return 0, 0, errors.New("limit undefined")
}

Expand All @@ -63,18 +62,18 @@ func (r *Range) Limits(len int) (s int, e int, _ error) {
} else {
if *r.Start < 0 {
// negative
s = len + *r.Start
s = length + *r.Start
} else {
s = *r.Start
}
}

if r.End == nil {
e = len - 1
e = length - 1
} else {
if *r.End < 0 {
// negative
e = len + *r.End
e = length + *r.End
} else {
e = *r.End
}
Expand All @@ -88,7 +87,7 @@ func (r *Range) Limits(len int) (s int, e int, _ error) {
return 0, 0, errors.New("range invalid")
}

if s >= len || e >= len {
if s >= length || e >= length {
return 0, 0, errors.New("range invalid")
}

Expand Down
2 changes: 1 addition & 1 deletion series_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ func TestSeriesSwap(t *testing.T) {
s := init[i]

s.Lock()
s.Swap(0, 2, Options{DontLock: true})
s.Swap(0, 2, DontLock)
s.Unlock()

exVals := expectedValues[i]
Expand Down
2 changes: 1 addition & 1 deletion sort.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (s *sorter) Less(i, j int) bool {
}

func (s *sorter) Swap(i, j int) {
s.df.swap(i, j)
s.df.Swap(i, j, DontLock)
}

// Sort is used to sort the data according to different keys
Expand Down
51 changes: 51 additions & 0 deletions utils/reverse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2019 PJ Engineering and Business Solutions Pty. Ltd. All rights reserved.

package utils

import (
"context"

dataframe "github.com/rocketlaunchr/dataframe-go"
)

type common interface {
Lock()
Unlock()
NRows(options ...dataframe.Options) int
Swap(row1, row2 int, options ...dataframe.Options)
}

// Reverse will reverse the order of a Dataframe or Series.
// If a Range is provided, only the rows within the range are reversed.
// s will be locked for the duration of the operation.
func Reverse(ctx context.Context, s common, r ...dataframe.Range) error {

s.Lock()
defer s.Unlock()

if len(r) == 0 {
r = append(r, dataframe.Range{})
}

nRows := s.NRows(dataframe.DontLock)
if nRows == 0 {
return nil
}

start, _, err := r[0].Limits(nRows)
if err != nil {
return err
}

rRows, _ := r[0].NRows(nRows)

for i := rRows/2 - 1; i >= 0; i-- {
if err := ctx.Err(); err != nil {
return err
}
opp := rRows - 1 - i
s.Swap(i+start, opp+start, dataframe.DontLock)
}

return nil
}
23 changes: 11 additions & 12 deletions search.go → utils/search.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
// Copyright 2018 PJ Engineering and Business Solutions Pty. Ltd. All rights reserved.

package dataframe
package utils

import (
"context"
"golang.org/x/sync/errgroup"
"runtime"
"sync"

"golang.org/x/sync/errgroup"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"

dataframe "github.com/rocketlaunchr/dataframe-go"
)

// Search is used to find particular values in a given Series.
Expand All @@ -25,16 +26,16 @@ import (
// fmt.Println(dataframe.Search(ctx, s1, int64(4), int64(6)))
// // Output: [5 6 11 12]
//
func Search(ctx context.Context, s Series, lower, upper interface{}, r ...Range) ([]int, error) {
func Search(ctx context.Context, s dataframe.Series, lower, upper interface{}, r ...dataframe.Range) ([]int, error) {

s.Lock()
defer s.Unlock()

if len(r) == 0 {
r = append(r, Range{})
r = append(r, dataframe.Range{})
}

fullRowCount := s.NRows(Options{DontLock: true})
fullRowCount := s.NRows(dataframe.DontLock)
if fullRowCount == 0 {
return []int{}, nil
}
Expand All @@ -54,22 +55,20 @@ func Search(ctx context.Context, s Series, lower, upper interface{}, r ...Range)
// Group search range equally amongst each core
div := (end - start + 1) / nCores

subRanges := []Range{}
subRanges := []dataframe.Range{}

for i := 0; i < nCores; i++ {
var subStart int
subStart := i * div
var subEnd int

if i != nCores-1 {
subStart = i * div
subEnd = (i+1)*div - 1
} else {
// last core
subStart = i * div
subEnd = end
}

subRanges = append(subRanges, Range{
subRanges = append(subRanges, dataframe.Range{
Start: &subStart,
End: &subEnd,
})
Expand Down Expand Up @@ -100,7 +99,7 @@ func Search(ctx context.Context, s Series, lower, upper interface{}, r ...Range)
return err
}

val := s.Value(row, Options{DontLock: true})
val := s.Value(row, dataframe.DontLock)

// Check if val is in range
if equalCheck {
Expand Down
55 changes: 55 additions & 0 deletions utils/shuffle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2019 PJ Engineering and Business Solutions Pty. Ltd. All rights reserved.

package utils

import (
"context"
"math/rand"
"time"

dataframe "github.com/rocketlaunchr/dataframe-go"
)

func init() {
rand.Seed(time.Now().UTC().UnixNano())
}

// Shuffle will randomly shuffle the rows in a Dataframe or Series.
// If a Range is provided, only the rows within the range are shuffled.
// s will be locked for the duration of the operation.
func Shuffle(ctx context.Context, s common, r ...dataframe.Range) (rErr error) {

defer func() {
if x := recover(); x != nil {
rErr = x.(error)
}
}()

s.Lock()
defer s.Unlock()

if len(r) == 0 {
r = append(r, dataframe.Range{})
}

nRows := s.NRows(dataframe.DontLock)
if nRows == 0 {
return nil
}

start, _, err := r[0].Limits(nRows)
if err != nil {
return err
}

rRows, _ := r[0].NRows(nRows)

rand.Shuffle(rRows, func(i, j int) {
if err := ctx.Err(); err != nil {
panic(err)
}
s.Swap(i+start, j+start, dataframe.DontLock)
})

return nil
}