github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/core/datamodel/sort.go (about)

     1  package datamodel
     2  
     3  import (
     4  	"sort"
     5  
     6  	rd "github.com/benoitkugler/goACVE/server/core/rawdata"
     7  )
     8  
     9  // Tri multicritère
    10  
    11  type Critere struct {
    12  	Field   rd.Field
    13  	Reverse bool
    14  }
    15  
    16  type CriteresTri struct {
    17  	skipDeterminisme bool
    18  	Fields           []Critere
    19  }
    20  
    21  const maxCriteres = 5
    22  
    23  // AddCritere renvoie la valeur mise à jour
    24  func (c CriteresTri) AddCritere(field rd.Field, reverse bool) CriteresTri {
    25  	if len(c.Fields) > 0 && c.Fields[0].Field == field {
    26  		// on n'ajoute pas le même champ, on met juste à jour l'ordre de tri
    27  		c.Fields[0].Reverse = reverse
    28  		return c
    29  	}
    30  	out := append([]Critere{{Field: field, Reverse: reverse}}, c.Fields...)
    31  	if len(out) > maxCriteres {
    32  		out = out[:maxCriteres]
    33  	}
    34  	return CriteresTri{Fields: out, skipDeterminisme: c.skipDeterminisme}
    35  }
    36  
    37  func (c CriteresTri) compare(itemi, itemj rd.Item) bool {
    38  	// si reverse vaut true on renvoie le contraire de b
    39  	// si reverse faut false on renvoie b
    40  
    41  	for _, field := range c.Fields {
    42  		vi := itemi.Fields.Data(field.Field).Sortable()
    43  		vj := itemj.Fields.Data(field.Field).Sortable()
    44  		if vi == vj { // on teste le critère suivant
    45  			continue
    46  		}
    47  		return field.Reverse != (vi < vj) // il n'y a plus égalité ici
    48  	}
    49  	if c.skipDeterminisme {
    50  		return false
    51  	}
    52  	return itemi.Id.Int64() < itemj.Id.Int64() // déterministe
    53  }
    54  
    55  // SortCriteresChilds modifie sur place `liste`
    56  // Le premier critère de `field` est le plus important.
    57  func SortCriteresChilds(liste []rd.ItemChilds, criteres CriteresTri) {
    58  	sort.Slice(liste, func(i, j int) bool {
    59  		return criteres.compare(liste[i].Item, liste[j].Item)
    60  	})
    61  }
    62  
    63  // SortCriteres modifie sur place `liste`
    64  // Le premier critère de `field` est le plus important.
    65  func SortCriteres(liste []rd.Item, criteres CriteresTri) {
    66  	sort.Slice(liste, func(i, j int) bool {
    67  		return criteres.compare(liste[i], liste[j])
    68  	})
    69  }
    70  
    71  // SortBy sorts `t` in place, accordind to field.
    72  func SortBy(t rd.Table, field rd.Field, rev bool) {
    73  	ct := CriteresTri{Fields: []Critere{{Field: field, Reverse: rev}}}
    74  	sort.Slice(t, func(i, j int) bool {
    75  		return ct.compare(t[i], t[j])
    76  	})
    77  }
    78  
    79  // SortStableBy sorts `t` in place.
    80  func SortStableBy(t rd.Table, field rd.Field, rev bool) {
    81  	ct := CriteresTri{Fields: []Critere{{Field: field, Reverse: rev}}, skipDeterminisme: true}
    82  	sort.SliceStable(t, func(i, j int) bool {
    83  		return ct.compare(t[i], t[j])
    84  	})
    85  }
    86  
    87  // Sort modifie sur place `liste`
    88  func Sort(liste rd.Table, headers []rd.Header, section int, reverse bool) {
    89  	field := headers[section].Field
    90  	SortBy(liste, field, reverse)
    91  }