整数区间计算,我这么设计

整数区间的交集和差集样例:

[1,5] + [6,10] = [1,10]

[1,100] - [10,20] = [1,9] + [21,100]

如果让你设计一个程序,能够计算整数区间的合集、交集、差集,你会怎么设计?

我会默默想想难度,然后去github上找找有没有可复用的开源代码。

go-intervals简介

go-intervals是一个用于在一维区间(例如时间范围)上执行集合操作的库,正好能满足我的整数区间计算需求。github地址为:https://github.com/google/go-intervals/

选用原因

之所以选择go-intervals有三个方面的考虑:

  1. 背靠谷歌金字招牌,足够让我相信代码质量

  2. 完整的测试用例

  3. 代码开源且易懂

代码剖析

go-intervals库能对多种一维区间集合进行操作,如时间、整数等;也能支持多种开闭区间,如左开右闭、左闭右开、左闭右闭等。代码是如何进行设计的呢?难道作者在代码内部实现了所有细节?

依赖倒转原则(DIP):高层模块不要依赖低层模块。高层模块和低层模块应该通过抽象(abstractions)来互相依赖。除此之外,抽象(abstractions)不要依赖具体实现细节(details),具体实现细节(details)依赖抽象(abstractions)。具体内容在Go设计模式(3)-设计原则有讲述。

思路:多个区间构成一个集合,区间是集合的基本单位。集合的交差并操作本质上是区间的交差并操作。

结合上面两点,作者的实现方式是将区间接口化。go-intervals只负责将在框架层面将两个集合的区间,两两进行交并差操作,交并差的实现逻辑由调用者自己实现。

type Interval interface {
  // Intersect returns the intersection of an interval with another
  // interval. The function may panic if the other interval is incompatible.
  //交集
  Intersect(Interval) Interval

  // Before returns true if the interval is completely before another interval.
  //一个区间是否在另一个区间前面
  Before(Interval) bool

  // IsZero returns true for the zero value of an interval.
  //是否为空区间
  IsZero() bool

  // Bisect returns two intervals, one on the lower side of x and one on the
  // upper side of x, corresponding to the subtraction of x from the original
  // interval. The returned intervals are always within the range of the
  // original interval.
  //差集
  Bisect(x Interval) (Interval, Interval)

  // Adjoin returns the union of two intervals, if the intervals are exactly
  // adjacent, or the zero interval if they are not.
  //并集
  Adjoin(Interval) Interval

  // Encompass returns an interval that covers the exact extents of two
  // intervals.
  //区间是否为包含关系
  Encompass(Interval) Interval
}

实现

调用者想实现哪种区间、哪种开闭方式,只需要实现自己的Interval即可。我需要实现整数、左闭右闭区间的并集、差集操作。

左闭右开区间

在代码的测试用例中,作者给出了整数区间,左闭右开的实现:

type span struct {
	min, max int
}

// case returns a *span from an Interval interface, or it panics.
func cast(i Interval) *span {
	x, ok := i.(*span)
	if !ok {
		panic(fmt.Errorf("interval must be an span: %v", i))
	}
	return x
}

// zero returns the zero value for span.
func zero() *span {
	return &span{}
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func (s *span) String() string {
	return fmt.Sprintf("[%d, %d)", s.min, s.max)
}

func (s *span) Equal(t *span) bool {
	return s.min == t.min && s.max == t.max
}

// Intersect returns the intersection of an interval with another
// interval. The function may panic if the other interval is incompatible.
func (s *span) Intersect(tInt Interval) Interval {
	t := cast(tInt)
	result := &span{
		max(s.min, t.min),
		min(s.max, t.max),
	}
	if result.min < result.max {
		return result
	}
	return zero()
}

// Before returns true if the interval is completely before another interval.
func (s *span) Before(tInt Interval) bool {
	t := cast(tInt)
	return s.max <= t.min
}

// IsZero returns true for the zero value of an interval.
func (s *span) IsZero() bool {
	return s.min == 0 && s.max == 0
}

// Bisect returns two intervals, one on either lower side of x and one on the
// upper side of x, corresponding to the subtraction of x from the original
// interval. The returned intervals are always within the range of the
// original interval.
func (s *span) Bisect(tInt Interval) (Interval, Interval) {
	intersection := cast(s.Intersect(tInt))
	if intersection.IsZero() {
		if s.Before(tInt) {
			return s, zero()
		}
		return zero(), s
	}
	maybeZero := func(min, max int) *span {
		if min == max {
			return zero()
		}
		return &span{min, max}
	}
	return maybeZero(s.min, intersection.min), maybeZero(intersection.max, s.max)

}

// Adjoin returns the union of two intervals, if the intervals are exactly
// adjacent, or the zero interval if they are not.
func (s *span) Adjoin(tInt Interval) Interval {
	t := cast(tInt)
	if s.max == t.min {
		return &span{s.min, t.max}
	}
	if t.max == s.min {
		return &span{t.min, s.max}
	}
	return zero()
}

// Encompass returns an interval that covers the exact extents of two
// intervals.
func (s *span) Encompass(tInt Interval) Interval {
	t := cast(tInt)
	return &span{min(s.min, t.min), max(s.max, t.max)}
}

左闭右闭区间

既然作者提供的不满足需求,就需要自己进行修改。参考左闭右开代码修改为左闭右闭代码,目前唯一的缺点是如果构建集合的区间有重叠会panic,重叠问题可以在业务层进行检查,倒也没什么问题。

type span struct {
   min, max int64
}

// case returns a *span from an Interval interface, or it panics.
func cast(i intervalset.Interval) *span {
   x, ok := i.(*span)
   if !ok {
      panic(fmt.Errorf("interval must be an span: %v", i))
   }
   return x
}

// zero returns the zero value for span.
func zero() *span {
   return &span{}
}

func min(a, b int64) int64 {
   if a < b {
      return a
   }
   return b
}

func max(a, b int64) int64 {
   if a > b {
      return a
   }
   return b
}

func (s *span) String() string {
   return fmt.Sprintf("[%d, %d]", s.min, s.max) //done
}

func (s *span) Equal(t *span) bool {
   return s.min == t.min && s.max == t.max
}

//已修改
// Before returns true if the interval is completely before another interval.
func (s *span) Before(tInt intervalset.Interval) bool {
   t := cast(tInt)
   //if s.min == s.max && s.max == t.min && t.min == t.max { //done
   // return false
   //}
   //if (s.min == s.max) && (s.min == t.min || s.min == t.max || s.max == t.min || s.max == t.max) {
   // return false
   //}
   //if (t.min == t.max) && (t.min == s.max || t.min == s.min || t.max == s.max || t.max == s.min) {
   // return false
   //}

   return s.max < t.min
}

// IsZero returns true for the zero value of an interval.
func (s *span) IsZero() bool {
   return s.min == 0 && s.max == 0
}

//交集 已修改
// Intersect returns the intersection of an interval with another
// interval. The function may panic if the other interval is incompatible.
func (s *span) Intersect(tInt intervalset.Interval) intervalset.Interval {
   t := cast(tInt)
   result := &span{
      max(s.min, t.min),
      min(s.max, t.max),
   }
   if result.min <= result.max { //done
      return result
   }
   return zero()
}

//相邻拼接  已修改
// Adjoin returns the union of two intervals, if the intervals are exactly
// adjacent, or the zero interval if they are not.
func (s *span) Adjoin(tInt intervalset.Interval) intervalset.Interval {
   t := cast(tInt)
   if s.max == t.min || s.max == t.min-1 { //done
      return &span{s.min, t.max}
   }
   if t.max == s.min || t.max == s.min-1 { //done
      return &span{t.min, s.max}
   }
   return zero()
}

//差集 已修改
// Bisect returns two intervals, one on either lower side of x and one on the
// upper side of x, corresponding to the subtraction of x from the original
// interval. The returned intervals are always within the range of the
// original interval.
func (s *span) Bisect(tInt intervalset.Interval) (intervalset.Interval, intervalset.Interval) {
   intersection := cast(s.Intersect(tInt))
   if intersection.IsZero() {
      if s.Before(tInt) {
         return s, zero()
      }
      return zero(), s
   }
   maybeZero := func(min, max int64) *span {
      if min > max { //done
         return zero()
      }
      return &span{min, max}
   }
   return maybeZero(s.min, intersection.min-1), maybeZero(intersection.max+1, s.max) //done

}

// Encompass returns an interval that covers the exact extents of two
// intervals.
func (s *span) Encompass(tInt intervalset.Interval) intervalset.Interval {
   t := cast(tInt)
   return &span{min(s.min, t.min), max(s.max, t.max)}
}

测试

检验自己代码是否有问题有什么方法?至少有两点,一是代码review,二是单元测试。对于这种引入的第三方库、且自己实现部分逻辑,一定要做好单元测试,这是前人栽树后人乘凉的好事。

测试case整理如下:

图片

[20,40]为指定区间,用其它区间和指定区间进行交、差操作。竖线表示左右区间值一样。

写了一晚上测试用例,初步测试没有问题。

/**
@author: Jason Pang
@desc:
@date: 2021/7/1
**/
package service

import (
   "github.com/google/go-intervals/intervalset"
   "reflect"
   "testing"
)

func TestAddTest(t *testing.T) {
   type args struct {
      s1 *intervalset.Set
      s2 *intervalset.Set
   }
   tests := []struct {
      name    string
      args    args
      wantRes *intervalset.Set
   }{
      {
         name: "empty + empty = empty",
         args: args{
            s1: intervalset.NewSet([]intervalset.Interval{}),
            s2: intervalset.NewSet([]intervalset.Interval{}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{}),
      },
      {
         name: "empty + [30,111] = [30, 111]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{}),
            intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
      },
      {
         name: "[20, 40] + empty = [20, 40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20, 40] + [60,111]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{60, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}, &span{60, 111}}),
      },
      {
         name: "[20, 40] + [39,111]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{39, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 111}}),
      },
      {
         name: "[20, 40] + [40,111]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{40, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 111}}),
      },
      {
         name: "[20, 40] + [41,111]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{41, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 111}}),
      },
      {
         name: "[20, 40] + [30,111]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 111}}),
      },
      {
         name: " [20,40] + [25, 28]  = [20,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{25, 28}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: " [20,40] + [10, 30]  = [10,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{10, 30}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 40}}),
      },
      {
         name: "[10, 19] + [20,40]  = [10,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{10, 19}}),
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 40}}),
      },
      {
         name: "[20,40] + [10, 20]  = [10,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{10, 20}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 40}}),
      },
      {
         name: "[20,40] + [10, 21]  = [10,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{10, 21}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 40}}),
      },
      {
         name: "[20,40] + [10, 15]  = [10,15] [20,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{10, 15}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 15}, &span{20, 40}}),
      },
      {
         name: "[20,40] + [10, 100]  = [10,100]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{10, 100}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 100}}),
      },
      {
         name: "[20,40] + [10, 10]  = [10,10] [20 40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{10, 10}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 10}, &span{20, 40}}),
      },
      {
         name: "[20,40] + [19, 19]  = [19 40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{19, 19}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{19, 40}}),
      },
      {
         name: "[20,40] + [20, 20]  = [20 40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20,40] + [21, 21]  = [20 40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{21, 21}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20,40] + [25, 25]  = [20 40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{25, 25}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20,40] + [39, 39]  = [20 40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{39, 39}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20,40] + [40, 40]  = [20 40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{40, 40}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20,40] + [41, 41]  = [20 41]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{41, 41}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 41}}),
      },
      {
         name: "[20,40] + [50, 50]  = [20 40] [50, 50] ",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{50, 50}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}, &span{50, 50}}),
      },
      /////////
      {
         name: "[20, 40] + [41,50]+ [50,60]+ [61,111] = [20,111]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}, &span{41, 50}}),
            intervalset.NewSet([]intervalset.Interval{&span{50, 60}, &span{61, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 111}}),
      },

      {
         name: "[10, 19] +  [20,20] = [10,20]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{10, 19}}),
            intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 20}}),
      },
      {
         name: " [20,20] + [10, 19]  = [10,20]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
            intervalset.NewSet([]intervalset.Interval{&span{10, 19}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 20}}),
      },
      {
         name: "[10, 19] + [21,30] + [20,20]  = [10,30]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{10, 19}, &span{21, 30}}),
            intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 30}}),
      },
      {
         name: "[10, 15] +  [20,20]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{10, 15}}),
            intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 15}, &span{20, 20}}),
      },
      {
         name: " [20,20] + [10, 15]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
            intervalset.NewSet([]intervalset.Interval{&span{10, 15}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 15}, &span{20, 20}}),
      },
   }
   for _, tt := range tests {
      t.Run(tt.name, func(t *testing.T) {
         if gotRes := AddTest(tt.args.s1, tt.args.s2); !reflect.DeepEqual(gotRes.AllIntervals(), tt.wantRes.AllIntervals()) {
            t.Errorf("Add() = %v, want %v", gotRes, tt.wantRes)
         }
      })
   }
}

func TestSubTest(t *testing.T) {
   type args struct {
      s1 *intervalset.Set
      s2 *intervalset.Set
   }
   tests := []struct {
      name    string
      args    args
      wantRes *intervalset.Set
   }{
      {
         name: "empty - empty = empty",
         args: args{
            s1: intervalset.NewSet([]intervalset.Interval{}),
            s2: intervalset.NewSet([]intervalset.Interval{}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{}),
      },
      {
         name: "empty - [30,111] = empty",
         args: args{
            intervalset.NewSet([]intervalset.Interval{}),
            intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{}),
      },
      {
         name: "[30,111] - empty = [30,111]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
            intervalset.NewSet([]intervalset.Interval{}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
      },
      {
         name: "[20, 40] - [30,111] = [20,29]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 29}}),
      },
      {
         name: "[20, 40] - [41,111] = [20,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{41, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20, 40] - [40,111] = [20,39]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{40, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 39}}),
      },
      {
         name: "[20, 40] - [39,111] = [20,38]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{39, 111}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 38}}),
      },
      {
         name: "[20, 40] - [25,28] = [20,24] [29,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{25, 28}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 24}, &span{29, 40}}),
      },
      {
         name: "[20, 40] - [15,28] = [29,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{15, 28}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{29, 40}}),
      },
      {
         name: "[20, 40] - [15,20] = [21,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{15, 20}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{21, 40}}),
      },
      {
         name: "[20, 40] - [15,21] = [22,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{15, 21}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{22, 40}}),
      },
      {
         name: "[20, 40] - [15,19] = [20,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{15, 19}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20, 40] - [10,15] = [20,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{10, 15}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20, 40] - [5,5] = [20,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{5, 5}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20, 40] - [20,20] = [21,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{21, 40}}),
      },
      {
         name: "[20, 40] - [25,25] = [20,24] [26,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{25, 25}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 24}, &span{26, 40}}),
      },
      {
         name: "[20, 40] - [40,40] = [20,39]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{40, 40}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 39}}),
      },
      {
         name: "[20, 40] - [45,45] = [20,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{45, 45}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20, 40] - [19,19] = [20,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{19, 19}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20, 40] - [21,21] = [20,20] [22,40] ",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{21, 21}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 20}, &span{22, 40}}),
      },
      {
         name: "[20, 40] - [39,39] = [20,38] [40, 40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{39, 39}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 38}, &span{40, 40}}),
      },
      {
         name: "[20, 40] - [41,41] = [20,40]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{41, 41}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
      },
      {
         name: "[20, 40] - [11,41] = []",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
            intervalset.NewSet([]intervalset.Interval{&span{11, 41}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{}),
      },
      {
         name: " [11,41] - [20, 40]  = [11,19] [41 41]",
         args: args{
            intervalset.NewSet([]intervalset.Interval{&span{11, 41}}),
            intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
         },
         wantRes: intervalset.NewSet([]intervalset.Interval{&span{11, 19}, &span{41, 41}}),
      },
   }
   for _, tt := range tests {
      t.Run(tt.name, func(t *testing.T) {
         if got := SubTest(tt.args.s1, tt.args.s2); !reflect.DeepEqual(got.AllIntervals(), tt.wantRes.AllIntervals()) {
            t.Errorf("Sub() = %v, want %v", got, tt.wantRes)
         }
      })
   }
}

总结

很多时候真的不需要重复造轮子,而且也难说自己造的比别人的好,合理合法利用资源、按时完成任务有时候更加重要。写代码是谨小慎微的事情,单元测试必不可少。不但能帮助自己理清思路、发现问题,也能防止后来人改出错误。

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的个人博客为:https://shidawuhen.github.io/

图片

往期文章回顾:

  1. 设计模式

  2. 招聘

  3. 思考

  4. 存储

  5. 算法系列

  6. 读书笔记

  7. 小工具

  8. 架构

  9. 网络

  10. Go语言

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员麻辣烫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值