-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsplit.go
More file actions
87 lines (84 loc) · 3.16 KB
/
Copy pathsplit.go
File metadata and controls
87 lines (84 loc) · 3.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package simplecsv
import "strings"
// SplitField replaces the column with the header name name by len(newNames)
// new columns in its position, and returns a new csv. Every data cell of
// the original column is split on sep with strings.Split, and the parts
// fill the new columns in order: if a cell has fewer parts than newNames,
// the remaining new columns get empty cells; if it has more parts, the
// extra parts are dropped. The original column is removed, so a new name
// may be the same as it but must not collide with any other header and the
// names in newNames must be unique. The header cell is replaced, never
// split. The original csv is not modified and the result shares no data
// with it. If the csv is empty, the field name does not exist, newNames is
// empty or contains duplicates, or a new name collides with another header,
// it returns a copy of the csv and false.
func (s SimpleCsv) SplitField(name, sep string, newNames []string) (SimpleCsv, bool) {
position := s.GetHeaderPosition(name)
if len(s) == 0 || position == -1 || len(newNames) == 0 || hasDuplicateHeaders(newNames) {
return s.fail()
}
for _, newName := range newNames {
if newName != name && s.GetHeaderPosition(newName) != -1 {
return s.fail()
}
}
newCsv := make(SimpleCsv, len(s))
for i, row := range s {
newRow := make([]string, 0, len(row)-1+len(newNames))
newRow = append(newRow, row[:position]...)
if i == 0 {
newRow = append(newRow, newNames...)
} else {
parts := strings.Split(row[position], sep)
for j := 0; j < len(newNames); j++ {
if j < len(parts) {
newRow = append(newRow, parts[j])
} else {
newRow = append(newRow, "")
}
}
}
newRow = append(newRow, row[position+1:]...)
newCsv[i] = newRow
}
return newCsv, true
}
// CombineFields appends a column with the header name as whose data cells
// join the values of the named columns with sep, and returns a new csv.
// The source columns stay in place; the new column is appended at the end.
// Every name in names must exist as a header, and names must not repeat a
// field. The header cells are never joined. The original csv is not
// modified and the result shares no data with it. If the csv is empty,
// names is empty, a name does not exist, names repeats a field, or as
// already exists as a header, it returns a copy of the csv and false.
func (s SimpleCsv) CombineFields(names []string, sep, as string) (SimpleCsv, bool) {
if len(s) == 0 || len(names) == 0 || s.GetHeaderPosition(as) != -1 {
return s.fail()
}
positions := make([]int, len(names))
seen := make(map[string]struct{}, len(names))
for i, field := range names {
if _, exists := seen[field]; exists {
return s.fail()
}
seen[field] = struct{}{}
position := s.GetHeaderPosition(field)
if position == -1 {
return s.fail()
}
positions[i] = position
}
newCsv := make(SimpleCsv, len(s))
newCsv[0] = append(copyRow(s[0]), as)
for i := 1; i < len(s); i++ {
parts := make([]string, len(names))
for j, position := range positions {
parts[j] = s[i][position]
}
newRow := make([]string, len(s[i])+1)
copy(newRow, s[i])
newRow[len(s[i])] = strings.Join(parts, sep)
newCsv[i] = newRow
}
return newCsv, true
}