dbtester/vendor/github.com/gyuho/dataframe/column.go

398 lines
7.9 KiB
Go

package dataframe
import (
"fmt"
"sort"
"sync"
)
// Column represents column-based data.
type Column interface {
// Count returns the number of rows of the Column.
Count() int
// Header returns the header of the Column.
Header() string
// Rows returns all the data in string slice.
Rows() []string
// UpdateHeader updates the header of the Column.
UpdateHeader(header string)
// Value returns the Value in the row. It returns error if the row
// is out of index range.
Value(row int) (Value, error)
// Set overwrites the value
Set(row int, v Value) error
// FindFirst finds the first Value, and returns the row number.
// It returns -1 and false if the value does not exist.
FindFirst(v Value) (int, bool)
// FindLast finds the last Value, and returns the row number.
// It returns -1 and false if the value does not exist.
FindLast(v Value) (int, bool)
// Front returns the first row Value.
Front() (Value, bool)
// FrontNonNil returns the first non-nil Value from the first row.
FrontNonNil() (Value, bool)
// Back returns the last row Value.
Back() (Value, bool)
// BackNonNil returns the first non-nil Value from the last row.
BackNonNil() (Value, bool)
// PushFront adds a Value to the front of the Column.
PushFront(v Value) int
// PushBack appends the Value to the Column.
PushBack(v Value) int
// Delete deletes a row by index.
Delete(row int) (Value, error)
// Deletes deletes rows by index [start, end).
Deletes(start, end int) error
// Keep keeps the rows by index [start, end).
Keep(start, end int) error
// PopFront deletes the value at front.
PopFront() (Value, bool)
// PopBack deletes the last value.
PopBack() (Value, bool)
// Appends adds the Value to the Column until it reaches the target size.
Appends(v Value, targetSize int) error
// Copy deep-copies a column.
Copy() Column
// SortByStringAscending sorts Column in string ascending order.
SortByStringAscending()
// SortByStringDescending sorts Column in string descending order.
SortByStringDescending()
// SortByNumberAscending sorts Column in number(float) ascending order.
SortByNumberAscending()
// SortByNumberDescending sorts Column in number(float) descending order.
SortByNumberDescending()
// SortByDurationAscending sorts Column in time.Duration ascending order.
SortByDurationAscending()
// SortByDurationDescending sorts Column in time.Duration descending order.
SortByDurationDescending()
}
type column struct {
mu sync.Mutex
header string
size int
data []Value
}
// NewColumn creates a new Column.
func NewColumn(hd string) Column {
return &column{
header: hd,
size: 0,
data: []Value{},
}
}
func (c *column) Count() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.size
}
func (c *column) Header() string {
c.mu.Lock()
defer c.mu.Unlock()
return c.header
}
func (c *column) Rows() (rows []string) {
c.mu.Lock()
defer c.mu.Unlock()
rows = make([]string, len(c.data))
for i := range c.data {
v, _ := c.data[i].String()
rows[i] = v
}
return
}
func (c *column) UpdateHeader(header string) {
c.mu.Lock()
defer c.mu.Unlock()
c.header = header
}
func (c *column) Value(row int) (Value, error) {
c.mu.Lock()
defer c.mu.Unlock()
if row > c.size-1 {
return nil, fmt.Errorf("index out of range (got %d for size %d)", row, c.size)
}
return c.data[row], nil
}
func (c *column) Set(row int, v Value) error {
c.mu.Lock()
defer c.mu.Unlock()
if row > c.size-1 {
return fmt.Errorf("index out of range (got %d for size %d)", row, c.size)
}
c.data[row] = v
return nil
}
func (c *column) FindFirst(v Value) (int, bool) {
c.mu.Lock()
defer c.mu.Unlock()
for i := range c.data {
if c.data[i].EqualTo(v) {
return i, true
}
}
return -1, false
}
func (c *column) FindLast(v Value) (int, bool) {
c.mu.Lock()
defer c.mu.Unlock()
var idx int
for i := range c.data {
if c.data[i].EqualTo(v) {
idx = i
}
}
if idx != 0 {
return idx, true
}
return -1, false
}
func (c *column) Front() (Value, bool) {
c.mu.Lock()
defer c.mu.Unlock()
if c.size == 0 {
return nil, false
}
v := c.data[0]
return v, true
}
func (c *column) FrontNonNil() (Value, bool) {
c.mu.Lock()
defer c.mu.Unlock()
if c.size == 0 {
return nil, false
}
for _, v := range c.data {
if !v.IsNil() {
return v, true
}
}
return nil, false
}
func (c *column) Back() (Value, bool) {
c.mu.Lock()
defer c.mu.Unlock()
if c.size == 0 {
return nil, false
}
v := c.data[c.size-1]
return v, true
}
func (c *column) BackNonNil() (Value, bool) {
c.mu.Lock()
defer c.mu.Unlock()
if c.size == 0 {
return nil, false
}
for i := c.size - 1; i > 0; i-- {
v := c.data[i]
if !v.IsNil() {
return v, true
}
}
return nil, false
}
func (c *column) PushFront(v Value) int {
c.mu.Lock()
defer c.mu.Unlock()
temp := make([]Value, c.size+1)
temp[0] = v
copy(temp[1:], c.data)
c.data = temp
c.size++
return c.size
}
func (c *column) PushBack(v Value) int {
c.mu.Lock()
defer c.mu.Unlock()
c.data = append(c.data, v)
c.size++
return c.size
}
func (c *column) Delete(row int) (Value, error) {
c.mu.Lock()
defer c.mu.Unlock()
if row > c.size-1 {
return nil, fmt.Errorf("index out of range (got %d for size %d)", row, c.size)
}
v := c.data[row]
copy(c.data[row:], c.data[row+1:])
c.data = c.data[:len(c.data)-1 : len(c.data)-1]
c.size--
return v, nil
}
func (c *column) Deletes(start, end int) error {
c.mu.Lock()
defer c.mu.Unlock()
if start < 0 || end < 0 || start > end {
return fmt.Errorf("wrong range %d %d", start, end)
}
if start > c.size {
return fmt.Errorf("index out of range (start %d, size %d)", start, c.size)
}
if end > c.size {
return fmt.Errorf("index out of range (end %d, size %d)", end, c.size)
}
if start == end {
return nil
}
delta := end - start
c.size = c.size - delta
var nds []Value
for i := range c.data {
if i >= start && i < end {
continue
}
nds = append(nds, c.data[i])
}
c.data = nds
return nil
}
func (c *column) Keep(start, end int) error {
c.mu.Lock()
defer c.mu.Unlock()
if start < 0 || end < 0 || start > end {
return fmt.Errorf("wrong range %d %d", start, end)
}
if start > c.size {
return fmt.Errorf("index out of range (start %d, size %d)", start, c.size)
}
if end > c.size {
return fmt.Errorf("index out of range (end %d, size %d)", end, c.size)
}
if start == end {
return nil
}
delta := end - start
c.size = delta
var nds []Value
for _, v := range c.data[start:end] {
nds = append(nds, v)
}
c.data = nds
return nil
}
func (c *column) PopFront() (Value, bool) {
c.mu.Lock()
defer c.mu.Unlock()
if c.size == 0 {
return nil, false
}
v := c.data[0]
c.data = c.data[1:len(c.data):len(c.data)]
c.size--
return v, true
}
func (c *column) PopBack() (Value, bool) {
c.mu.Lock()
defer c.mu.Unlock()
if c.size == 0 {
return nil, false
}
v := c.data[c.size-1]
c.data = c.data[:len(c.data)-1 : len(c.data)-1]
c.size--
return v, true
}
func (c *column) Appends(v Value, targetSize int) error {
c.mu.Lock()
defer c.mu.Unlock()
if c.size > 0 && c.size > targetSize {
return fmt.Errorf("cannot append with target size %d, which is less than the column size %d (can't overwrite)", targetSize, c.size)
}
for i := c.size; i < targetSize; i++ {
c.data = append(c.data, v)
c.size++
}
return nil
}
func (c *column) Copy() Column {
c2 := &column{
header: c.header,
size: c.size,
data: make([]Value, len(c.data)),
}
for i := range c.data {
c2.data[i] = c.data[i].Copy()
}
return c2
}
func (c *column) SortByStringAscending() { sort.Sort(ByStringAscending(c.data)) }
func (c *column) SortByStringDescending() { sort.Sort(ByStringDescending(c.data)) }
func (c *column) SortByNumberAscending() { sort.Sort(ByNumberAscending(c.data)) }
func (c *column) SortByNumberDescending() { sort.Sort(ByNumberDescending(c.data)) }
func (c *column) SortByDurationAscending() { sort.Sort(ByDurationAscending(c.data)) }
func (c *column) SortByDurationDescending() { sort.Sort(ByDurationDescending(c.data)) }