Desde Go 1.21 hay un paquete slices en la biblioteca estándar que hace casi todo esto en una línea. Sustituye al viejo sort, que sigue funcionando pero pedía bastante más ceremonia.
También te puede interesar
Lo más simple
nums := []int{7, 2, 9, 4, 2}
slices.Sort(nums)
fmt.Println(nums)
salida[2 2 4 7 9]
Ordena en el sitio: no devuelve nada, modifica el slice que le pasas. Si necesitas conservar el original, slices.Sort(slices.Clone(nums)).
Y con cadenas, cuidado
nombres := []string{"Marta", "ana", "Luis"}
slices.Sort(nombres)
fmt.Println(nombres)
salida[Luis Marta ana]
«ana» va al final. No es un fallo: la comparación es por el valor de los caracteres, y las mayúsculas van antes que las minúsculas. Si quieres el orden que espera una persona, hay que decirlo:
slices.SortFunc(nombres, func(a, b string) int {
return strings.Compare(strings.ToLower(a), strings.ToLower(b))
})
salida[ana Luis Marta]
Ordenar structs
SortFunc recibe una función que compara dos elementos y devuelve un número: negativo si el primero va antes, positivo si va después, cero si da igual.
slices.SortFunc(ps, func(a, b Producto) int {
if a.Precio < b.Precio {
return -1
}
if a.Precio > b.Precio {
return 1
}
return 0
})
salidaBufanda 9.00 2 Gorra 12.50 7 Camiseta 19.90 3 Mochila 34.00 7
return a.Unidades - b.Unidades. Con float64 no, porque la resta no es un int; y con enteros muy grandes tampoco, porque la resta puede desbordar. Las tres comparaciones son siempre seguras.Por dos criterios
slices.SortFunc(ps, func(a, b Producto) int {
if a.Unidades != b.Unidades {
return b.Unidades - a.Unidades // más unidades primero
}
return strings.Compare(a.Nombre, b.Nombre) // y a igualdad, por nombre
})
salidaGorra 7 Mochila 7 Camiseta 3 Bufanda 2
El patrón es siempre ese: comprueba el primer criterio y, solo si empata, pasa al siguiente. Fíjate en que el orden descendente se consigue invirtiendo la resta, b - a.
Buscar
ord := []int{2, 2, 4, 7, 9}
fmt.Println(slices.Contains(ord, 7))
fmt.Println(slices.Index(ord, 4))
i, hay := slices.BinarySearch(ord, 7)
fmt.Printf("posición %d, encontrado %v\n", i, hay)
i, hay = slices.BinarySearch(ord, 5)
fmt.Printf("posición %d, encontrado %v\n", i, hay)
salidatrue 2 posición 3, encontrado true posición 3, encontrado false
Las dos primeras recorren el slice de principio a fin y valen para cualquiera. BinarySearch es mucho más rápida pero exige que el slice esté ordenado; sobre uno desordenado no da error, da una respuesta equivocada.
Y fíjate en la última línea: buscando el 5, que no está, devuelve 3 y false. Ese 3 es la posición donde habría que insertarlo para mantener el orden, que es justo lo que necesitas para insertar ordenado.
El resto del paquete
fmt.Println(slices.Max(ord), slices.Min(ord)) fmt.Println(slices.Compact(slices.Clone(ord))) // quita duplicados seguidos slices.Reverse(nums)
salida9 2 [2 4 7 9]
Compact elimina los repetidos consecutivos, así que solo sirve para quitar duplicados si antes has ordenado. Es la misma lógica del uniq de Unix.
El paquete sort, por si lo ves
sort.Ints(viejo)
sort.Strings(nombres)
sort.Slice(ps, func(i, j int) bool { return ps[i].Precio < ps[j].Precio })
Sigue funcionando y hay muchísimo código escrito con él. Las diferencias: sort.Slice recibe índices en vez de elementos y devuelve un bool en vez de un número. Para código nuevo, slices.
| Para | Usa |
|---|---|
| Ordenar números o cadenas | slices.Sort |
| Ordenar por un criterio propio | slices.SortFunc |
| Mantener el orden de los empatados | slices.SortStableFunc |
| Saber si está | slices.Contains |
| Buscar en algo ya ordenado | slices.BinarySearch |
| Máximo y mínimo | slices.Max, slices.Min |
| Quitar duplicados | Ordenar y luego slices.Compact |
Todo el código se compiló y ejecutó con Go 1.25 antes de publicarla; las salidas están copiadas de esa ejecución. Documentación oficial: paquete slices.