Estou encarregado de reescrever algum código VB antigo. Entendo como funciona, mas sinto que há uma maneira muito mais eficiente de fazer o que eles fizeram. Eu simplesmente não consigo descobrir o que é. Aqui está um exemplo artificial que, em termos de requisitos de dados, é realmente semelhante ao que eu preciso fazer.
O usuário deve escolher o fabricante, marca, modelo e cor do seu carro em uma GUI. Eu tenho um arquivo de texto grande que se parece com isso:
Ford Truck F150 red
Ford Truck F150 blue
Ford Truck F150 black
Ford Truck F150 silver
Ford Truck F250 red
Ford Truck F250 green
Ford Sedan Taurus red
Ford Sedan Taurus green
Ford Sedan Taurus white
Ford...
...
Subaru SUV Forester blue
Subaru SUV Forester red
Subaru SUV Outback Black
Subaru SUV Outback Green
Subaru SUV Outback Blue
Subaru SUV Outback Red
Subaru...
...
etc.
Portanto, se a primeira seleção for Subaru, a segunda caixa (marca) não deverá ter a opção de selecionar Caminhão porque nenhum dos Subarus é caminhão. Da mesma forma, se eles selecionam Ford, Sedan e Taurus, a última caixa (cor) não deve mostrar uma opção para selecionar azul. Ou preto. Ou qualquer coisa que não seja vermelho, verde ou branco.
As pessoas que escreveram o código antes de mim vieram com isso (em python-y psuedocode):
def getValidOptions():
items = []
for i from 0 to numRows:
options = getLine().split()
if selectingManufacturer:
if options[0] not in items:
items.append(options[0])
else if selectingMake:
if selectedManufacturer == options[0] and options[1] not in items:
items.append(options[1])
else if selectingModel:
if selectedManufacturer == options[0] and selectedMake == options[1] and options[2] not in items:
items.append(options[2])
else if selectingColor:
if selectedManufacturer == options[0] and selectedMake == options[1] and selectedModel == options[2] and options[3] not in items:
items.append(options[3])
return items
Eu acho isso hediondo, tanto no nível de algoritmos quanto no nível de sintaxe. Por um lado, ele analisa o arquivo inteiro, quando só precisa ler algumas linhas, se bem. Para tornar isso ainda mais ineficiente, meus dados reais têm 6 opções para selecionar, em vez de apenas 4. Isso também está armazenando mais dados do que é necessário, dada a quantidade de duplicação de dados.
Estou procurando uma maneira diferente de armazenar os dados no arquivo ou uma maneira diferente de analisá-los para tornar a getValidOptions
função mais bonita e mais eficiente. Há alguma maneira de eu fazer isso?
Respostas:
Todas as outras respostas que li parecem ignorar duas regras muito básicas de desenvolvimento de software:
esclareça primeiro os requisitos (especialmente os requisitos de desempenho e armazenamento)
Mantenha as coisas simples, estúpidas (veja KISS )
Você escreveu "o arquivo de texto é grande", mas não escreveu muito grande, portanto, presumo que não há nada de errado com seu tamanho, exceto seu pressentimento. Portanto, se o carregamento do arquivo não demorar, o departamento de TI ou alguém não reclamar do espaço em disco desperdiçado e ninguém reclamar de problemas para manter o arquivo, deixe o formato do arquivo como está - não subestime valor da simplicidade.
Você também está reclamando da eficiência do algoritmo, que na verdade não é tão eficiente quanto poderia ser, mas tem uma grande vantagem: é simples, com morte encefálica e funciona. Portanto, desde que seja eficiente o suficiente, não aplique nenhuma otimização prematura.
Então, vamos supor que o programa funcione rápido o suficiente, o que você deve perguntar primeiro é como você pode melhorar o código em termos de simplicidade e do princípio DRY? E esse é realmente um ponto que deve ser aprimorado, pois o código atual não é SECO. No seu exemplo, aparece quase quatro vezes o mesmo teste de bloco de código se as opções nos "níveis mais altos" corresponderem à linha atual, o que resulta em quatro vezes o mesmo tipo de chamada "anexar" (no seu código real, a repetição ocorre pelo menos seis vezes, como você escreveu). Você pode evitar isso facilmente introduzindo um nível de seleção numérica ou passando as opções já selecionadas em uma lista ordenada. Usando seu pseudo-código, isso leva a algo ao longo das linhas de
Portanto, este é essencialmente o mesmo algoritmo sem código repetido.
Como é óbvio
getValidOptions
que deve ser chamado mais de uma vez (pelo menos uma vez por nível), sugiro aplicar apenas uma otimização (se esse ainda não for o caso): verifique se agetLine
função extrai seus dados da memória principal e não leia o arquivo do disco novamente e novamente.fonte
Bem, os dados que você possui têm uma estrutura de árvore, onde para cada fabricante você tem uma árvore de modelos e para cada modelo você tem uma cor (e assim por diante).
Portanto, você pode separar o processo desses dados de duas etapas:
A estrutura em árvore pode ser implementada com o que é chamado de hash , uma matriz associativa ou um dicionário em linguagens como Java, PHP, Javascript ou Python. Com essa estrutura, você tem:
Dependendo da sua linguagem de programação, isso pode ser implementado mais rápido ou mais devagar. Por exemplo:
Runtime.Serialization.Formatters.Binary.BinaryFormatter
poderia ser útil, mas não sou especialista em serializar com o VB.Net.Class
que implemente a interfacejava.io.Serializable
.Referências :
1: https://dvanderboom.wordpress.com/2008/03/15/treet-implementing-a-non-binary-tree-in-c/
- Uma explicação completa sobre a implementação de uma árvore em C #.
- Procure um comentário em que alguém pergunte sobre serializar esse objeto e a resposta para esse comentário.
fonte
tree with an arbitrary number of nodes
implementação.Uma maneira simples de armazenar os dados é inseri-los em um banco de dados SQLite. O SQLite, diferentemente da maioria dos bancos de dados SQL, é adequado para uso como um formato de arquivo de aplicativo. Essa abordagem tem vários benefícios:
select distinct model where manufacturer='ford' and color = 'red'
).Isso força você a aprender SQL, mas evita a necessidade de aprender um formato de arquivo personalizado.
fonte
Presumo que você possa acessar linhas aleatoriamente no arquivo e, portanto, possa tratá-lo como uma matriz de registros. Se você não puder acessar as linhas aleatoriamente, o algoritmo que você possui é o melhor que você pode fazer.
Para acesso mais rápido, armazene os dados em 6 arquivos, onde cada arquivo é um índice para o próximo.
Existem várias maneiras de criar índices flatfile. Eu costumo usar um intervalo de subscritos. À medida que o usuário faz cada seleção, use o intervalo para limitar a leitura do próximo arquivo.
Aqui está como eu criaria os índices para os dados de amostra que você forneceu.
Claro que o arquivo deve ser classificado. Eu numerei as linhas para ilustração; os números das linhas não devem aparecer no arquivo.
Para criar o primeiro índice, faça um registro para cada combinação exclusiva dos três primeiros campos no arquivo. Em cada registro, armazene o primeiro e o último número de linha em que essa combinação aparece.
O segundo índice é construído da mesma forma, usando os dois primeiros campos do primeiro índice.
E o terceiro, o nível superior, neste caso, índice.
Acho que estou superexplicando o conceito, mas em geral você cria um índice eliminando o último campo e eliminando registros duplicados.
Você pode reduzir ainda mais os requisitos de armazenamento de arquivos, eliminando alguns dados redundantes.
Por exemplo, o "primeiro" subscrito em cada registro de índice é sempre um a mais que o "último" subscrito do registro anterior, ou zero se não houver registro anterior. Portanto, você não precisa armazenar os "primeiros" subscritos. Estou deixando-os no lugar abaixo para ilustração.
Além disso, como você usará apenas o último campo em cada registro para preencher a lista de seleção, não será necessário armazenar os outros campos.
A renderização mínima da cascata de índices acaba sendo assim, onde o tick 'indica um número realmente não armazenado no arquivo.
Ao preencher uma lista de seleção de um índice, você usa os subscritos "primeiro" e "último" da seleção do usuário no índice anterior para limitar as linhas lidas.
Exemplo:
Você preenche a primeira lista de seleção de todos
file0.dat
. (Ford, Subaru)O usuário seleciona "Ford". Os subscritos correspondentes são 0 e 1.
Você preenche a segunda lista de seleção das linhas 0 a 1 de
file1.dat
. (Caminhão, Sedan)O usuário seleciona "Sedan". Os subscritos correspondentes são 2 e 2.
Como você pode ver, no momento em que o usuário selecionou, por exemplo, "Ford" "Sedan" "Taurus", você encontrará que precisa ler apenas as linhas 6 a 8
file3.dat
para preencher a quarta lista de seleção.Peço desculpas pela descrição bastante longa, mas é muito tarde aqui e não tenho tempo para escrever uma breve.
ADICIONADO: Pensando melhor, os arquivos podem ser concatenados em um.
Isso é usado exatamente como a versão de vários arquivos, exceto que você precisa da primeira linha fictícia para conter o primeiro intervalo de subscritos.
fonte