-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdiff.go
More file actions
69 lines (67 loc) · 2.38 KB
/
Copy pathdiff.go
File metadata and controls
69 lines (67 loc) · 2.38 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
package simplecsv
import "slices"
// DiffByKey compares the data rows of s (left) and other (right), keyed by
// the values of the column with the header name key. It returns three new
// csvs:
//
// - added: the data rows of other whose key is not present in s, with
// other's header row
// - removed: the data rows of s whose key is not present in other, with
// s's header row
// - changed: the data rows of s whose key is present in other but whose
// full row differs, with s's header row and s's values (callers that
// want the right-side values can join on the key)
//
// The rows keep their order of appearance in the source csv. The key values
// must be unique within each csv: a key repeated in s or in other makes the
// diff ambiguous, and it returns nil, nil, nil and false. It also returns
// nil, nil, nil and false if either csv is empty or the key is not a header
// name in either csv. A csv with only the header row is a valid input (all
// the other side's rows are then added or removed). The original csvs are
// not modified and the results share no data with them.
func (s SimpleCsv) DiffByKey(other SimpleCsv, key string) (added, removed, changed SimpleCsv, ok bool) {
if len(s) == 0 || len(other) == 0 {
return nil, nil, nil, false
}
leftPos := s.GetHeaderPosition(key)
if leftPos == -1 {
return nil, nil, nil, false
}
rightPos := other.GetHeaderPosition(key)
if rightPos == -1 {
return nil, nil, nil, false
}
leftRows := make(map[string]int, len(s)-1)
for i := 1; i < len(s); i++ {
if _, exists := leftRows[s[i][leftPos]]; exists {
return nil, nil, nil, false
}
leftRows[s[i][leftPos]] = i
}
rightRows := make(map[string]int, len(other)-1)
for i := 1; i < len(other); i++ {
if _, exists := rightRows[other[i][rightPos]]; exists {
return nil, nil, nil, false
}
rightRows[other[i][rightPos]] = i
}
added = SimpleCsv{copyRow(other[0])}
removed = SimpleCsv{copyRow(s[0])}
changed = SimpleCsv{copyRow(s[0])}
for i := 1; i < len(other); i++ {
if _, exists := leftRows[other[i][rightPos]]; !exists {
added = append(added, copyRow(other[i]))
}
}
for i := 1; i < len(s); i++ {
rightIndex, exists := rightRows[s[i][leftPos]]
if !exists {
removed = append(removed, copyRow(s[i]))
continue
}
if !slices.Equal(s[i], other[rightIndex]) {
changed = append(changed, copyRow(s[i]))
}
}
return added, removed, changed, true
}