Refactor Slice Utils as Variadic Functions (#3206)

* variadic approach working

* transform to variadic

* comments

* all variadic funcs simplified and tests passing
This commit is contained in:
Raul Jordan 2019-08-14 17:08:53 -05:00 committed by GitHub
parent c0627e29a8
commit 65ee6eb3af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 144 additions and 137 deletions

View File

@ -25,40 +25,54 @@ func SubsetUint64(a []uint64, b []uint64) bool {
return true
}
// IntersectionUint64 of two uint64 slices with time
// IntersectionUint64 of any number of uint64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func IntersectionUint64(a []uint64, b []uint64) []uint64 {
set := make([]uint64, 0)
m := make(map[uint64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
func IntersectionUint64(s ...[]uint64) []uint64 {
if len(s) == 0 {
return []uint64{}
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; found {
set = append(set, b[i])
if len(s) == 1 {
return s[0]
}
intersect := make([]uint64, 0)
for i := 1; i < len(s); i++ {
m := make(map[uint64]bool)
for j := 0; j < len(s[i-1]); j++ {
m[s[i-1][j]] = true
}
for j := 0; j < len(s[i]); j++ {
if _, found := m[s[i][j]]; found {
intersect = append(intersect, s[i][j])
}
}
}
return set
return intersect
}
// UnionUint64 of two uint64 slices with time
// UnionUint64 of any number of uint64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func UnionUint64(a []uint64, b []uint64) []uint64 {
func UnionUint64(s ...[]uint64) []uint64 {
if len(s) == 0 {
return []uint64{}
}
if len(s) == 1 {
return s[0]
}
set := make([]uint64, 0)
m := make(map[uint64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
set = append(set, a[i])
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; !found {
set = append(set, b[i])
for i := 1; i < len(s); i++ {
for j := 0; j < len(s[i-1]); j++ {
m[s[i-1][j]] = true
set = append(set, s[i-1][j])
}
for j := 0; j < len(s[i]); j++ {
if _, found := m[s[i][j]]; !found {
set = append(set, s[i][j])
}
}
}
return set
@ -106,40 +120,54 @@ func IsInUint64(a uint64, b []uint64) bool {
return false
}
// IntersectionInt64 of two int64 slices with time
// IntersectionInt64 of any number of int64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func IntersectionInt64(a []int64, b []int64) []int64 {
func IntersectionInt64(s ...[]int64) []int64 {
if len(s) == 0 {
return []int64{}
}
if len(s) == 1 {
return s[0]
}
set := make([]int64, 0)
m := make(map[int64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; found {
set = append(set, b[i])
for i := 1; i < len(s); i++ {
for j := 0; j < len(s[i-1]); j++ {
m[s[i-1][j]] = true
}
for j := 0; j < len(s[i]); j++ {
if _, found := m[s[i][j]]; found {
set = append(set, s[i][j])
}
}
}
return set
}
// UnionInt64 of two int64 slices with time
// UnionInt64 of any number of int64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func UnionInt64(a []int64, b []int64) []int64 {
func UnionInt64(s ...[]int64) []int64 {
if len(s) == 0 {
return []int64{}
}
if len(s) == 1 {
return s[0]
}
set := make([]int64, 0)
m := make(map[int64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
set = append(set, a[i])
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; !found {
set = append(set, b[i])
for i := 1; i < len(s); i++ {
for j := 0; j < len(s[i-1]); j++ {
m[s[i-1][j]] = true
set = append(set, s[i-1][j])
}
for j := 0; j < len(s[i]); j++ {
if _, found := m[s[i][j]]; !found {
set = append(set, s[i][j])
}
}
}
return set
@ -174,44 +202,35 @@ func IsInInt64(a int64, b []int64) bool {
return false
}
// IntersectionByteSlices returns the common elements between two
// sets of byte slices.
func IntersectionByteSlices(s1, s2 [][]byte) [][]byte {
hash := make(map[string]bool)
for _, e := range s1 {
hash[string(e)] = true
}
inter := make([][]byte, 0)
for _, e := range s2 {
if hash[string(e)] {
inter = append(inter, e)
}
}
// Remove duplicates from slice.
deduped := make([][]byte, 0)
encountered := make(map[string]bool)
for _, element := range inter {
if !encountered[string(element)] {
deduped = append(deduped, element)
encountered[string(element)] = true
}
}
return deduped
}
// TotalIntersectionByteSlices takes in a set of byte slices
// and determines the intersection of common elements across all of them,
// returning a single slice of byte slices.
func TotalIntersectionByteSlices(sets [][][]byte) [][]byte {
if len(sets) == 0 {
// IntersectionByteSlices returns the common elements between sets of byte slices.
func IntersectionByteSlices(s ...[][]byte) [][]byte {
if len(s) == 0 {
return [][]byte{}
}
if len(sets) == 1 {
return sets[0]
if len(s) == 1 {
return s[0]
}
intersected := IntersectionByteSlices(sets[0], sets[1])
for i := 2; i < len(sets); i++ {
intersected = IntersectionByteSlices(intersected, sets[i])
inter := make([][]byte, 0)
for i := 1; i < len(s); i++ {
hash := make(map[string]bool)
for _, e := range s[i-1] {
hash[string(e)] = true
}
for _, e := range s[i] {
if hash[string(e)] {
inter = append(inter, e)
}
}
tmp := make([][]byte, 0)
// Remove duplicates from slice.
encountered := make(map[string]bool)
for _, element := range inter {
if !encountered[string(element)] {
tmp = append(tmp, element)
encountered[string(element)] = true
}
}
inter = tmp
}
return intersected
return inter
}

View File

@ -228,81 +228,69 @@ func TestIsInInt64(t *testing.T) {
func TestIntersectionByteSlices(t *testing.T) {
testCases := []struct {
a [][]byte
b [][]byte
input [][][]byte
result [][]byte
}{
{[][]byte{{1, 2, 3}, {4, 5}}, [][]byte{{1, 2}, {4, 5}}, [][]byte{{4, 5}}},
// Ensure duplicate elements are moved in the resulting set.
{[][]byte{{1, 2, 3}, {4, 5}, {4, 5}}, [][]byte{{1, 2}, {4, 5}, {4, 5}}, [][]byte{{4, 5}}},
{
input: [][][]byte{
{
{1, 2, 3},
{4, 5},
},
{
{1, 2},
{4, 5},
},
},
result: [][]byte{{4, 5}},
},
// Ensure duplicate elements are removed in the resulting set.
{
input: [][][]byte{
{
{1, 2, 3},
{4, 5},
{4, 5},
},
{
{1, 2},
{4, 5},
{4, 5},
},
},
result: [][]byte{{4, 5}},
},
// Ensure no intersection returns an empty set.
{[][]byte{{1, 2, 3}, {4, 5}}, [][]byte{{1, 2}}, [][]byte{}},
{
input: [][][]byte{
{
{1, 2, 3},
{4, 5},
},
{
{1, 2},
},
},
result: [][]byte{},
},
// Intersection between A and A should return A.
{[][]byte{{1, 2}}, [][]byte{{1, 2}}, [][]byte{{1, 2}}},
}
for _, tt := range testCases {
result := IntersectionByteSlices(tt.a, tt.b)
if !reflect.DeepEqual(result, tt.result) {
t.Errorf("IntersectionByteSlices(%v, %v)=%v, wanted: %v",
tt.a, tt.b, result, tt.result)
}
}
}
func TestTotalIntersectionByteSlices(t *testing.T) {
testCases := []struct {
a [][][]byte
result [][]byte
}{
{
[][][]byte{
input: [][][]byte{
{
{1, 2, 3},
{4, 5},
{1, 2},
},
{
{4, 5},
},
{
{4, 5},
{6, 7, 8},
{9, 10, 11},
{1, 2},
},
},
[][]byte{
{4, 5},
},
},
{
[][][]byte{
{
{1, 2, 3},
{4, 5},
},
},
[][]byte{
{1, 2, 3},
{4, 5},
},
},
{
[][][]byte{
{
{1, 2, 3},
{4, 5},
},
{
{6},
},
},
[][]byte{},
result: [][]byte{{1, 2}},
},
}
for _, tt := range testCases {
result := TotalIntersectionByteSlices(tt.a)
result := IntersectionByteSlices(tt.input...)
if !reflect.DeepEqual(result, tt.result) {
t.Errorf("TotalIntersectionByteSlices(%v)=%v, wanted: %v",
tt.a, result, tt.result)
t.Errorf("IntersectionByteSlices(%v)=%v, wanted: %v",
tt.input, result, tt.result)
}
}
}