domingo, 13 de abril de 2014

Como ordenar o conteúdo de um Memo com regras personalizadas

Recentemente um colega delpheiro me perguntou como ordenar um memo não pelo seu conteúdo, mas por alguma regra especial.

No caso dele, ele tinha no memo várias strings separadas por ":" com números do outro lado. Algo assim:

A:3
B:5
C:1

Devendo ficar:

C:1
A:3
B:5

Para isso podemos usar a função CustomSort do memo, passando como argumento uma função. Essa é uma função especial que aceita uma lista como parâmetro, dois índices da lista e retorna um integer. Assim ela pode comparar dois itens da lista e retornar 1 se o primeiro for maior, 0 se os itens forem iguais ou -1 se o segundo for maior.
Essa função é que fará todo o trabalho de comparação, portanto você decide como os itens serão comparados. A função CustomSort saberá que deve chamar a sua função para decidir, na varredura, qual item é maior porque você passará o nome da sua função, como se fosse um delegate ou ponteiro para função, como argumento para  a função customsort.

Os memos podem ser usados como dictionaries, ou como arquivos ini, eles podem ter pares de namve/value, e para isso você define a propriedade NameValueSeparator. Definindo esta propriedade como ":" os valores são automaticamente separados em duas partes.

O código ficou como abaixo:

//crio uma function inline que compara só dois valores e diz qual é o maior
//ela é usada automaticamente para comparar os valores 2 a 2 dentro da função
//customsort do stringlist e ordenar a parada toda
function compara(List: TStringList; Index1, Index2: Integer): Integer;
var val1: integer;
val2: integer;
begin

  //defino que o separador e chave / valor NameValueSeparator é ':', a string separadora.
  List.NameValueSeparator := ':';
  val1 :=  StrToInt( List.ValueFromIndex[Index1]);
  val2 := StrToInt( List.ValueFromIndex[Index2]);

  //quando você coloca o delimitador de um tstringlist  você pode separar ele em key e value
  //essa função pode ser anonima
  //se o valor do indice 1 for maior que o 2 retorna 1
  if(val1 > val2) then
    Result := 1
  //se for menor retorna -1
  else if(val2 > val1) then
    Result := -1
  else
    //se for igual retorna zero
    Result := 0;

  //esses resultados -1, 0 e  1 são o padrão de todos os comparers
end;



procedure TForm1.Button1Click(Sender: TObject);
  //crio um stringlist temporário para guardar o conteudo ordenado
  var str: TStringList;

begin
  str := TStringList.Create;

  //mando  o conteudo do memo para o stringlist
  str.AddStrings(Memo1.Lines);

  //mando ordenar passando como parâmetro a função ordenadora (existem
  //funções que aceitam outras funções como parâmetro, não o retorno dela, mas seu escopo, ela será executada internamente)
  str.CustomSort( compara );

  //limpa  o  memo1
  Memo1.Clear;

  //adiciona o valor ja ordenado
  Memo1.Lines.AddStrings(str);

  //destroi o stringlist
  str.Free;
end;


Have fun :)

Um comentário:

  1. Bom dia.
    Parabéns pelo post.
    Sou estudante de programação pelo curso adv, www.cursoadv.com.br
    Muito obrigado pela dica, é muito bom contar com esse material complementar.

    ResponderExcluir

Postagens populares

Marcadores

delphi (60) C# (31) poo (21) Lazarus (19) Site aos Pedaços (15) sql (13) Reflexões (10) .Net (9) Humor (9) javascript (9) ASp.Net (8) api (8) Básico (6) Programação (6) ms sql server (5) Web (4) banco de dados (4) HTML (3) PHP (3) Python (3) design patterns (3) jQuery (3) livros (3) metaprogramação (3) Ajax (2) Debug (2) Dicas Básicas Windows (2) Pascal (2) games (2) linguagem (2) música (2) singleton (2) tecnologia (2) Anime (1) Api do Windows (1) Assembly (1) Eventos (1) Experts (1) GNU (1) Inglês (1) JSON (1) SO (1) datas (1) developers (1) dicas (1) easter egg (1) firebird (1) interfaces (1) introspecção (1) memo (1) oracle (1) reflexão (1)