Autohotkey versão 2 - Ordenação topológica (Array, Map, Função recursiva, Grafo)
É um artigo?
Sei que alguns aqui tem grandes ambições e anseiam por artigos.
Porém já aviso que isto não é um artigo.
O que é Autohotkey?
Autohotkey é uma linguagem de script poderosa usada para automatizar aplicativos desktops, mapear teclas ou criar scripts que auxiliam durante a jogatina de games, não é popular mas fornece alta produtividade para quem sabe usar, também se destaca em tarefas que em outras linguagens seria mais complicado além de ter que escrever muito mais código.
Motivação
Quero apenas compartilhar um código que tentei codificar do zero, porém falhei, demorei a encontrar e o tornei mais inteligível e enxuto.
Na empresa havia sempre o mesmo problema, scripts sql's que geravam arquivos .csv deviam ser chamados na ordem correta, era comum um depender do outro, havendo uma certa hierarquia, quando uma tabela não retornava dados era a dúvida de sempre, será que não está na ordem de execução correta, ou será alguma condição?
Segue uma possível solução:
#Requires AutoHotkey v2.0+
#SingleInstance
gestores := Map()
gestores["municipio"] := ["estado", "governo"]
gestores["pai"] := ["empresa"]
gestores["filho"] := ["mae", "pai"]
gestores["estado"] := ["governo"]
gestores["mae"] := ["empresa"]
gestores["governo"] := []
gestores["empresa"] := ["municipio", "estado", "governo"]
try {
resultado_array := ordena_topologicamente(gestores)
MsgBox array_para_string(resultado_array, "`n"), "Ordenação topológica", "Iconi"
} catch Error as falha {
MsgBox falha.message "`n Linha: " falha.Line, "Falha: " falha.What, "IconX"
} ; end try
ordena_topologicamente(gestores) {
array_ordenado := [], rastro_map := Map(), ja_foi_ordenado_map := Map()
for elemento in gestores
if not ja_foi_ordenado_map.Has(elemento)
ordene(elemento, gestores, array_ordenado, rastro_map, ja_foi_ordenado_map)
return array_ordenado
} ; end function
ordene(elemento, gestores, array_ordenado, rastro_map , ja_foi_ordenado_map) {
if rastro_map.Has(elemento)
throw Error("Dependência cíclica, causando loop infinito!", "ordene()")
if not ja_foi_ordenado_map.Has(elemento) {
rastro_map[elemento] := true
if not gestores.has(elemento)
throw Error(" Elemento (" elemento ") do array `n não encontrado no Map() gestores!", "ordene()")
for elemento in gestores[elemento]
ordene(elemento, gestores, array_ordenado, rastro_map, ja_foi_ordenado_map)
rastro_map.Delete(elemento)
ja_foi_ordenado_map[elemento] := true
array_ordenado.Push(elemento)
} ; end if
} ; end function
array_para_string(array, separador := ", ") {
resultado := ""
for elemento in array
resultado .= separador elemento
return LTrim(resultado, separador)
} ; end function
Resultado
Ei, não está faltando coisa?
Muitos vão dizer, e com razão, que o código não lê .csv, etc.
Verdade, o código real é ainda mais complexo pois a estrutura com os dados é formada de forma dinâmica, etc. o que demonstro aqui é só a função principal, a parte mais complexa do código do todo.
Para quê esse código em uma linguagem que "ninguém" usa?
Realmente, como eu disse Autohotkey não é muito popular, no entanto, acredito que não será difícil adaptar para linguagem com funcionalidades semelhantes (map, array e função).