123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- // package lcs provides functions to calculate Longest Common Subsequence (LCS)
- // values from two arbitrary arrays.
- package lcs
- import (
- "context"
- "reflect"
- )
- // Lcs is the interface to calculate the LCS of two arrays.
- type Lcs interface {
- // Values calculates the LCS value of the two arrays.
- Values() (values []interface{})
- // ValueContext is a context aware version of Values()
- ValuesContext(ctx context.Context) (values []interface{}, err error)
- // IndexPairs calculates paris of indices which have the same value in LCS.
- IndexPairs() (pairs []IndexPair)
- // IndexPairsContext is a context aware version of IndexPairs()
- IndexPairsContext(ctx context.Context) (pairs []IndexPair, err error)
- // Length calculates the length of the LCS.
- Length() (length int)
- // LengthContext is a context aware version of Length()
- LengthContext(ctx context.Context) (length int, err error)
- // Left returns one of the two arrays to be compared.
- Left() (leftValues []interface{})
- // Right returns the other of the two arrays to be compared.
- Right() (righttValues []interface{})
- }
- // IndexPair represents an pair of indeices in the Left and Right arrays found in the LCS value.
- type IndexPair struct {
- Left int
- Right int
- }
- type lcs struct {
- left []interface{}
- right []interface{}
- /* for caching */
- table [][]int
- indexPairs []IndexPair
- values []interface{}
- }
- // New creates a new LCS calculator from two arrays.
- func New(left, right []interface{}) Lcs {
- return &lcs{
- left: left,
- right: right,
- table: nil,
- indexPairs: nil,
- values: nil,
- }
- }
- // Table implements Lcs.Table()
- func (lcs *lcs) Table() (table [][]int) {
- table, _ = lcs.TableContext(context.Background())
- return table
- }
- // Table implements Lcs.TableContext()
- func (lcs *lcs) TableContext(ctx context.Context) (table [][]int, err error) {
- if lcs.table != nil {
- return lcs.table, nil
- }
- sizeX := len(lcs.left) + 1
- sizeY := len(lcs.right) + 1
- table = make([][]int, sizeX)
- for x := 0; x < sizeX; x++ {
- table[x] = make([]int, sizeY)
- }
- for y := 1; y < sizeY; y++ {
- select { // check in each y to save some time
- case <-ctx.Done():
- return nil, ctx.Err()
- default:
- // nop
- }
- for x := 1; x < sizeX; x++ {
- increment := 0
- if reflect.DeepEqual(lcs.left[x-1], lcs.right[y-1]) {
- increment = 1
- }
- table[x][y] = max(table[x-1][y-1]+increment, table[x-1][y], table[x][y-1])
- }
- }
- lcs.table = table
- return table, nil
- }
- // Table implements Lcs.Length()
- func (lcs *lcs) Length() (length int) {
- length, _ = lcs.LengthContext(context.Background())
- return length
- }
- // Table implements Lcs.LengthContext()
- func (lcs *lcs) LengthContext(ctx context.Context) (length int, err error) {
- table, err := lcs.TableContext(ctx)
- if err != nil {
- return 0, err
- }
- return table[len(lcs.left)][len(lcs.right)], nil
- }
- // Table implements Lcs.IndexPairs()
- func (lcs *lcs) IndexPairs() (pairs []IndexPair) {
- pairs, _ = lcs.IndexPairsContext(context.Background())
- return pairs
- }
- // Table implements Lcs.IndexPairsContext()
- func (lcs *lcs) IndexPairsContext(ctx context.Context) (pairs []IndexPair, err error) {
- if lcs.indexPairs != nil {
- return lcs.indexPairs, nil
- }
- table, err := lcs.TableContext(ctx)
- if err != nil {
- return nil, err
- }
- pairs = make([]IndexPair, table[len(table)-1][len(table[0])-1])
- for x, y := len(lcs.left), len(lcs.right); x > 0 && y > 0; {
- if reflect.DeepEqual(lcs.left[x-1], lcs.right[y-1]) {
- pairs[table[x][y]-1] = IndexPair{Left: x - 1, Right: y - 1}
- x--
- y--
- } else {
- if table[x-1][y] >= table[x][y-1] {
- x--
- } else {
- y--
- }
- }
- }
- lcs.indexPairs = pairs
- return pairs, nil
- }
- // Table implements Lcs.Values()
- func (lcs *lcs) Values() (values []interface{}) {
- values, _ = lcs.ValuesContext(context.Background())
- return values
- }
- // Table implements Lcs.ValuesContext()
- func (lcs *lcs) ValuesContext(ctx context.Context) (values []interface{}, err error) {
- if lcs.values != nil {
- return lcs.values, nil
- }
- pairs, err := lcs.IndexPairsContext(ctx)
- if err != nil {
- return nil, err
- }
- values = make([]interface{}, len(pairs))
- for i, pair := range pairs {
- values[i] = lcs.left[pair.Left]
- }
- lcs.values = values
- return values, nil
- }
- // Table implements Lcs.Left()
- func (lcs *lcs) Left() (leftValues []interface{}) {
- leftValues = lcs.left
- return
- }
- // Table implements Lcs.Right()
- func (lcs *lcs) Right() (rightValues []interface{}) {
- rightValues = lcs.right
- return
- }
- func max(first int, rest ...int) (max int) {
- max = first
- for _, value := range rest {
- if value > max {
- max = value
- }
- }
- return
- }
|