Back-End

21 jul, 2008

Ordenando estruturas com sort

Publicidade

A ordenação flexível em Perl é um dos pontos que mais me chama a atenção na tecnologia, pois permite que uma estrutura (um vetor ou hash, por exemplo) sejam ordenados utilizando uma função de ordenação que é aplicada para todos os elementos da estrutura, fazendo com que uma lógica extremamente complexa possa ser utilizada de forma simples e dinâmica.

Antes de exemplos, dois operadores são especialmente úteis: cmp para comparação de cadeias de caracteres e <=> para comparação de valores numéricos. Ambos comparam dois elementos e retornam o valor 0, caso os valores sejam iguais, -1, caso o valor à esquerda seja menor ou então 1, caso o valor à esquerda seja maior. Deve-se entender menor e maior para textos, tendo como base a tabela ASCII.


$esquerda = 30;
$direita = 20;
print ´Valor: ´ . ($esquerda <=> $direita); # Valor: 1

$esquerda = 10;
$direita = 20;
print ´Valor: ´ . ($esquerda <=> $direita);  #Valor: -1

Generalizando essa idéia para conjuntos de valores e imaginando que essa operação será aplicada sempre a cada dois elementos do vetor e utilizando algum método de ordenação, o resultado final é um vetor ordenado conforme a regra estabelecida. Antes de chegar ao vetor ordenado, um outro conceito é importante no processo: as variáveis especiais $a e $b. Elas representam dois valores que serão usando pelas funções de ordenação. Elas podem representar os próprios elementos ou mesmo chaves de um hash. Segue um primeiro exemplo:


@vetor = (10, 9, 5, 7, 3, 2);
print join(´, ´, sort @vetor); # imprime a seguinte saida: 10, 2, 3, 5, 7, 9

Repare que o valor dez, ainda que seja numericamente devesse ser colocado ao final da lista, aparece logo na primeira posição, pois a aplicação da função sort, levou em consideração os elementos como cadeias de caracteres, o que fez a ordenação trazer os elementos começados por 1 para o início. Evoluindo o exemplo:


@vetor = (10, 9, 5, 7, 3, 20, 2);
print join(´, ´, sort {$a <=> $b} @vetor); # imprime a seguinte saida: 2, 3, 5, 7, 9, 10, 20

Repare o uso do sort, mas a função padrão foi substituída por um trecho de código que mostra de que forma os elementos comparados devem ser testados. A cada comparação dos elementos, as variáveis $a e $b assumem dois valores do conjunto, até que todo o vetor esteja ordenado. Por fim, segue o caso geral:


# criacao de um hash
%pessoas = ();
$pessoas{´123´} = ´Marcelo´;
$pessoas{´456´} = ´Joao´;
$pessoas{´789´} = ´Fulano´;

foreach my $valor (sort funcao_comparacao keys %pessoas) {
  print $pessoas{$valor} . " ";
}

# definicao de uma funcao de ordenacao
sub funcao_comparacao {
  $pessoas{$a} cmp $pessoas{$b};
}

No exemplo acima, foi criado um hash, onde as chaves eram um código qualquer (numa aplicação real, poderia ser o número do CPF das pessoas) e o valor o nome das pessoas. Essa coleção foi percorrida usando um foreach e ao mesmo tempo os elementos já foram ordenados tomando como base a funcao_comparacao, que recebeu como argumento, as chaves do hash. A implementação dessa função traz a comparação de cada nome, que pôde ser encontrado devido à passagem da chave como parâmetro.