Introdução
Ordenar dados é uma das operações mais comuns em programação. Zig oferece funções de ordenação eficientes na biblioteca padrão através do módulo std.mem, permitindo ordenar qualquer tipo de dado com funções de comparação customizadas.
Nesta receita, você aprenderá a ordenar arrays de números, strings e structs.
Pré-requisitos
- Zig instalado (versão 0.13+). Veja o guia de instalação
- Conhecimento básico de Zig. Consulte a introdução ao Zig
Ordenar Array de Números
A forma mais simples de ordenar:
const std = @import("std");
pub fn main() !void {
var numeros = [_]i32{ 42, 17, 8, 95, 3, 61, 28, 54, 12, 76 };
std.debug.print("Original: ", .{});
for (numeros) |n| std.debug.print("{d} ", .{n});
std.debug.print("\n", .{});
// Ordenar em ordem crescente
std.mem.sort(i32, &numeros, {}, std.sort.asc(i32));
std.debug.print("Crescente: ", .{});
for (numeros) |n| std.debug.print("{d} ", .{n});
std.debug.print("\n", .{});
// Ordenar em ordem decrescente
std.mem.sort(i32, &numeros, {}, std.sort.desc(i32));
std.debug.print("Decresc.: ", .{});
for (numeros) |n| std.debug.print("{d} ", .{n});
std.debug.print("\n", .{});
}
Saída esperada
Original: 42 17 8 95 3 61 28 54 12 76
Crescente: 3 8 12 17 28 42 54 61 76 95
Decresc.: 95 76 61 54 42 28 17 12 8 3
Ordenar com Função de Comparação Customizada
Para lógica de ordenação personalizada:
const std = @import("std");
pub fn main() !void {
// Ordenar por valor absoluto
var numeros = [_]i32{ -5, 3, -1, 4, -2, 0, 7, -6 };
std.mem.sort(i32, &numeros, {}, struct {
fn compare(_: void, a: i32, b: i32) bool {
const abs_a = if (a < 0) -a else a;
const abs_b = if (b < 0) -b else b;
return abs_a < abs_b;
}
}.compare);
std.debug.print("Por valor absoluto: ", .{});
for (numeros) |n| std.debug.print("{d} ", .{n});
std.debug.print("\n", .{});
// Ordenar pares antes de ímpares
var nums2 = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std.mem.sort(i32, &nums2, {}, struct {
fn compare(_: void, a: i32, b: i32) bool {
const a_par = @mod(a, 2) == 0;
const b_par = @mod(b, 2) == 0;
if (a_par and !b_par) return true;
if (!a_par and b_par) return false;
return a < b;
}
}.compare);
std.debug.print("Pares primeiro: ", .{});
for (nums2) |n| std.debug.print("{d} ", .{n});
std.debug.print("\n", .{});
}
Ordenar Strings
Ordenar um array de strings lexicograficamente:
const std = @import("std");
pub fn main() !void {
var frutas = [_][]const u8{
"uva",
"banana",
"abacaxi",
"manga",
"cereja",
"laranja",
};
std.mem.sort([]const u8, &frutas, {}, struct {
fn compare(_: void, a: []const u8, b: []const u8) bool {
return std.mem.order(u8, a, b) == .lt;
}
}.compare);
std.debug.print("Frutas ordenadas:\n", .{});
for (frutas, 1..) |fruta, i| {
std.debug.print(" {d}. {s}\n", .{ i, fruta });
}
}
Ordenar Structs
Ordenar uma lista de structs por campo:
const std = @import("std");
const Aluno = struct {
nome: []const u8,
nota: f64,
idade: u32,
};
pub fn main() !void {
var alunos = [_]Aluno{
.{ .nome = "Maria", .nota = 9.5, .idade = 22 },
.{ .nome = "João", .nota = 7.8, .idade = 20 },
.{ .nome = "Ana", .nota = 9.5, .idade = 21 },
.{ .nome = "Pedro", .nota = 8.2, .idade = 23 },
.{ .nome = "Lucas", .nota = 6.9, .idade = 19 },
};
// Ordenar por nota (decrescente)
std.mem.sort(Aluno, &alunos, {}, struct {
fn compare(_: void, a: Aluno, b: Aluno) bool {
return a.nota > b.nota;
}
}.compare);
std.debug.print("Ranking por nota:\n", .{});
for (alunos, 1..) |aluno, i| {
std.debug.print(" {d}. {s} - nota {d:.1}\n", .{ i, aluno.nome, aluno.nota });
}
// Ordenar por nome
std.mem.sort(Aluno, &alunos, {}, struct {
fn compare(_: void, a: Aluno, b: Aluno) bool {
return std.mem.order(u8, a.nome, b.nome) == .lt;
}
}.compare);
std.debug.print("\nPor nome:\n", .{});
for (alunos) |aluno| {
std.debug.print(" {s} (nota {d:.1}, {d} anos)\n", .{ aluno.nome, aluno.nota, aluno.idade });
}
}
Verificar se Array Está Ordenado
const std = @import("std");
fn estaOrdenado(comptime T: type, items: []const T) bool {
if (items.len <= 1) return true;
for (items[0 .. items.len - 1], items[1..]) |a, b| {
if (a > b) return false;
}
return true;
}
pub fn main() !void {
const ord = [_]i32{ 1, 2, 3, 4, 5 };
const desord = [_]i32{ 3, 1, 4, 1, 5 };
std.debug.print("[1,2,3,4,5] ordenado? {}\n", .{estaOrdenado(i32, &ord)});
std.debug.print("[3,1,4,1,5] ordenado? {}\n", .{estaOrdenado(i32, &desord)});
}
Ordenar ArrayList
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var lista = std.ArrayList(f64).init(allocator);
defer lista.deinit();
try lista.appendSlice(&[_]f64{ 3.14, 1.41, 2.71, 0.57, 1.73 });
// Ordenar os items do ArrayList
std.mem.sort(f64, lista.items, {}, std.sort.asc(f64));
std.debug.print("Ordenado: ", .{});
for (lista.items) |v| {
std.debug.print("{d:.2} ", .{v});
}
std.debug.print("\n", .{});
}
Dicas e Boas Práticas
A ordenação é estável:
std.mem.sortpreserva a ordem relativa de elementos iguais.Use
std.sort.asc/desc: Para tipos primitivos, essas funções prontas são mais limpas.Contexto via parâmetro: O terceiro parâmetro de
sortpassa contexto para a função de comparação. Use{}quando não precisa de contexto.Slices são referências: A ordenação modifica o array/slice original in-place.
Receitas Relacionadas
- Busca Binária - Buscar em arrays ordenados
- Filtrar Arrays - Filtrar antes de ordenar
- Arrays Dinâmicos com ArrayList - Listas dinâmicas
- Comparar Strings - Comparação de texto