Otimização de Diff
Otimização de Diff
Este guia mostra como limpar um diff bruto — uma lista de DiffOperation valores (veja Diff para como eles são construídos) — em uma forma canônica e mínima usando as passagens de pós-processamento no DiffOptimization sub-namespace. Cada passagem implementa IDiffOptimizationOperation e altera a lista de diff no local, permitindo que as passagens sejam encadeadas em sequência para simplificar progressivamente o resultado.
O contrato de otimização
IDiffOptimizationOperation define um único método, Execute(diffs), que normaliza uma lista mutável de valores DiffOperation in-place enquanto preserva os textos de origem e destino que o diff representa. Cada otimizador neste sub-namespace implementa essa interface, de forma que podem ser invocados de maneira intercambiável ou compostos em um pipeline.
List<DiffOperation> diffs = new List<DiffOperation>
{
new DiffOperation(Operation.Equal, "The quick "),
new DiffOperation(Operation.Delete, "brown "),
new DiffOperation(Operation.Insert, "red "),
new DiffOperation(Operation.Equal, "fox")
};
IDiffOptimizationOperation optimizer = new OperationsMerger(EditOperationsOrder.DeleteFirst);
optimizer.Execute(diffs);Mesclando operações adjacentes
OperationsMerger mescla um diff em sua forma canônica mínima: ele combina sequências adjacentes do mesmo tipo de operação, e para uma sequência mista de exclusão/inserção ele extrai qualquer prefixo comum para a igualdade anterior e qualquer sufixo comum para a igualdade subsequente.
var merger = new OperationsMerger(EditOperationsOrder.DeleteFirst);
merger.Execute(diffs);Eliminando igualdades curtas
MergingOptimizer executa uma passagem de limpeza semântica: elimina igualdades que não são maiores que as edições ao seu redor, dobrando essas curtas sequências comuns de volta nas exclusões/inserções adjacentes e, em seguida, remescla o resultado na forma canônica.
var semanticOptimizer = new MergingOptimizer(EditOperationsOrder.InsertFirst);
semanticOptimizer.Execute(diffs);Deslizando edições ao longo de igualdades
OperationsSlideMerger desloca lateralmente uma única edição que está cercada por igualdades em ambos os lados, removendo uma dessas igualdades e aprimorando ainda mais a forma canônica da diferença.
IDiffOptimizationOperation slideMerger = new OperationsSlideMerger();
slideMerger.Execute(diffs);Controlando a ordem de delete/insert
Quando uma exclusão e uma inserção são emitidas para a mesma posição, o enum EditOperationsOrder define qual delas o otimizador coloca primeiro na sequência de operações resultante: DeleteFirst ou InsertFirst.
var order = EditOperationsOrder.DeleteFirst;
var optimizer = new MergingOptimizer(order);
optimizer.Execute(diffs);Dicas e boas práticas
- Execute
OperationsMergerprimeiro para agrupar edições brutas antes de aplicar as passagens semânticas —MergingOptimizereOperationsSlideMergerpressupõem que operações semelhantes próximas já foram combinadas. - Escolha um valor de
EditOperationsOrdere utilize-o de forma consistente em todos os otimizadores de um pipeline; misturarDeleteFirsteInsertFirstentre as passagens pode desfazer a ordem estabelecida por uma passagem anterior. - Todos os três otimizadores alteram o
List<DiffOperation>no local — clone a lista primeiro se precisar manter o diff não otimizado para comparação. - Como cada otimizador implementa
IDiffOptimizationOperation, você pode manter um pipeline comoIDiffOptimizationOperation[]e chamarExecuteem cada um dentro de um loop, em vez de codificar manualmente cada passagem pelo nome. - Aplique
OperationsSlideMergerapós as passagens de mesclagem — deslizar uma edição só é útil depois que blocos adjacentes do mesmo tipo já foram coalescidos.
Problemas comuns
| Problema | Causa | Correção |
|---|---|---|
| A diferença ainda contém pequenas igualdades fragmentadas | Só OperationsMerger foi executado; pequenas igualdades entre edições nunca foram compactadas | Execute também MergingOptimizer após OperationsMerger |
| A ordem de exclusão/inserção inverte inesperadamente entre as passagens | Valores diferentes de EditOperationsOrder foram passados para otimizadores diferentes | Use o mesmo valor de EditOperationsOrder para cada otimizador no pipeline |
| O otimizador parece não ter efeito | A lista de diferenças já estava em forma canônica, ou uma cópia da lista foi otimizada em vez da referência original | Confirme que está passando a mesma referência List<DiffOperation> que o código downstream lê |
FAQ
O que significa “forma canônica” para um diff?
Significa que operações consecutivas do mesmo tipo foram coalescidas e qualquer prefixo/sufixo comum em sequências misturadas de exclusão/inserção foi incorporado à igualdade vizinha, de modo que a sequência não possui fragmentação redundante.
Preciso usar os três otimizadores?
Não. IDiffOptimizationOperation permite que você aplique apenas as passagens necessárias, mas executar OperationsMerger antes das passagens semânticas (MergingOptimizer, OperationsSlideMerger) produz os resultados mais consistentes.
Qual é a diferença entre OperationsMerger e MergingOptimizer?
OperationsMerger realiza a coalescência estrutural (sequências de mesmo tipo, prefixo/sufixo comum). MergingOptimizer aprofunda o processo e incorpora pequenas igualdades cercadas por alterações ao bloco de exclusão/inserção vizinho antes de fazer a nova fusão.
O EditOperationsOrder altera o que o diff representa?
Não. Ele apenas controla a ordem de emissão de uma exclusão e de uma inserção que se aplicam ao mesmo ponto — a reconstrução final do texto permanece inalterada.
API Reference Resumo
| Classe / Método | Descrição |
|---|---|
IDiffOptimizationOperation | Interface para uma passagem de pós-processamento que normaliza um diff no local |
IDiffOptimizationOperation.Execute(diffs) | Executa a passagem de otimização sobre uma lista mutável de valores DiffOperation |
OperationsMerger | Agrupa operações vizinhas da mesma categoria e transforma prefixos/sufixos comuns em igualdades |
MergingOptimizer | Elimina equalidades curtas cercadas por edições, então refunde em forma canônica |
OperationsSlideMerger | Desloca uma edição cercada por equalidades para eliminar uma delas |
EditOperationsOrder | Enum que controla se DeleteFirst ou InsertFirst é emitido em uma posição compartilhada |