golcs.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // package lcs provides functions to calculate Longest Common Subsequence (LCS)
  2. // values from two arbitrary arrays.
  3. package lcs
  4. import (
  5. "context"
  6. "reflect"
  7. )
  8. // Lcs is the interface to calculate the LCS of two arrays.
  9. type Lcs interface {
  10. // Values calculates the LCS value of the two arrays.
  11. Values() (values []interface{})
  12. // ValueContext is a context aware version of Values()
  13. ValuesContext(ctx context.Context) (values []interface{}, err error)
  14. // IndexPairs calculates paris of indices which have the same value in LCS.
  15. IndexPairs() (pairs []IndexPair)
  16. // IndexPairsContext is a context aware version of IndexPairs()
  17. IndexPairsContext(ctx context.Context) (pairs []IndexPair, err error)
  18. // Length calculates the length of the LCS.
  19. Length() (length int)
  20. // LengthContext is a context aware version of Length()
  21. LengthContext(ctx context.Context) (length int, err error)
  22. // Left returns one of the two arrays to be compared.
  23. Left() (leftValues []interface{})
  24. // Right returns the other of the two arrays to be compared.
  25. Right() (righttValues []interface{})
  26. }
  27. // IndexPair represents an pair of indeices in the Left and Right arrays found in the LCS value.
  28. type IndexPair struct {
  29. Left int
  30. Right int
  31. }
  32. type lcs struct {
  33. left []interface{}
  34. right []interface{}
  35. /* for caching */
  36. table [][]int
  37. indexPairs []IndexPair
  38. values []interface{}
  39. }
  40. // New creates a new LCS calculator from two arrays.
  41. func New(left, right []interface{}) Lcs {
  42. return &lcs{
  43. left: left,
  44. right: right,
  45. table: nil,
  46. indexPairs: nil,
  47. values: nil,
  48. }
  49. }
  50. // Table implements Lcs.Table()
  51. func (lcs *lcs) Table() (table [][]int) {
  52. table, _ = lcs.TableContext(context.Background())
  53. return table
  54. }
  55. // Table implements Lcs.TableContext()
  56. func (lcs *lcs) TableContext(ctx context.Context) (table [][]int, err error) {
  57. if lcs.table != nil {
  58. return lcs.table, nil
  59. }
  60. sizeX := len(lcs.left) + 1
  61. sizeY := len(lcs.right) + 1
  62. table = make([][]int, sizeX)
  63. for x := 0; x < sizeX; x++ {
  64. table[x] = make([]int, sizeY)
  65. }
  66. for y := 1; y < sizeY; y++ {
  67. select { // check in each y to save some time
  68. case <-ctx.Done():
  69. return nil, ctx.Err()
  70. default:
  71. // nop
  72. }
  73. for x := 1; x < sizeX; x++ {
  74. increment := 0
  75. if reflect.DeepEqual(lcs.left[x-1], lcs.right[y-1]) {
  76. increment = 1
  77. }
  78. table[x][y] = max(table[x-1][y-1]+increment, table[x-1][y], table[x][y-1])
  79. }
  80. }
  81. lcs.table = table
  82. return table, nil
  83. }
  84. // Table implements Lcs.Length()
  85. func (lcs *lcs) Length() (length int) {
  86. length, _ = lcs.LengthContext(context.Background())
  87. return length
  88. }
  89. // Table implements Lcs.LengthContext()
  90. func (lcs *lcs) LengthContext(ctx context.Context) (length int, err error) {
  91. table, err := lcs.TableContext(ctx)
  92. if err != nil {
  93. return 0, err
  94. }
  95. return table[len(lcs.left)][len(lcs.right)], nil
  96. }
  97. // Table implements Lcs.IndexPairs()
  98. func (lcs *lcs) IndexPairs() (pairs []IndexPair) {
  99. pairs, _ = lcs.IndexPairsContext(context.Background())
  100. return pairs
  101. }
  102. // Table implements Lcs.IndexPairsContext()
  103. func (lcs *lcs) IndexPairsContext(ctx context.Context) (pairs []IndexPair, err error) {
  104. if lcs.indexPairs != nil {
  105. return lcs.indexPairs, nil
  106. }
  107. table, err := lcs.TableContext(ctx)
  108. if err != nil {
  109. return nil, err
  110. }
  111. pairs = make([]IndexPair, table[len(table)-1][len(table[0])-1])
  112. for x, y := len(lcs.left), len(lcs.right); x > 0 && y > 0; {
  113. if reflect.DeepEqual(lcs.left[x-1], lcs.right[y-1]) {
  114. pairs[table[x][y]-1] = IndexPair{Left: x - 1, Right: y - 1}
  115. x--
  116. y--
  117. } else {
  118. if table[x-1][y] >= table[x][y-1] {
  119. x--
  120. } else {
  121. y--
  122. }
  123. }
  124. }
  125. lcs.indexPairs = pairs
  126. return pairs, nil
  127. }
  128. // Table implements Lcs.Values()
  129. func (lcs *lcs) Values() (values []interface{}) {
  130. values, _ = lcs.ValuesContext(context.Background())
  131. return values
  132. }
  133. // Table implements Lcs.ValuesContext()
  134. func (lcs *lcs) ValuesContext(ctx context.Context) (values []interface{}, err error) {
  135. if lcs.values != nil {
  136. return lcs.values, nil
  137. }
  138. pairs, err := lcs.IndexPairsContext(ctx)
  139. if err != nil {
  140. return nil, err
  141. }
  142. values = make([]interface{}, len(pairs))
  143. for i, pair := range pairs {
  144. values[i] = lcs.left[pair.Left]
  145. }
  146. lcs.values = values
  147. return values, nil
  148. }
  149. // Table implements Lcs.Left()
  150. func (lcs *lcs) Left() (leftValues []interface{}) {
  151. leftValues = lcs.left
  152. return
  153. }
  154. // Table implements Lcs.Right()
  155. func (lcs *lcs) Right() (rightValues []interface{}) {
  156. rightValues = lcs.right
  157. return
  158. }
  159. func max(first int, rest ...int) (max int) {
  160. max = first
  161. for _, value := range rest {
  162. if value > max {
  163. max = value
  164. }
  165. }
  166. return
  167. }