.
Em uma macro com Loop
é melhor deixar ela extensa e com testes únicos para cada situação,
ou menor porem mais complexa e com mais testes?
Somente é impossíveis até que alguém faça
A logica está presa na irracionalidade humana, e morta nos que se consideram donos da verdade.
"ALGUM MODERADOR ME EXPULSE DO FÓRUM POR FAVOR"
Somente Loop é um pouco generico, depende de que tipo estamos falando, e da mesma forma dos IF conforme o que pretendemos, na medida do possível qualquer rotina é preferível dividir, em VBA podemos reescrever diversas rotinas para obter o mesmo fim, depende de qde de dados e processamento.
Um Loop se associado a condições de comparação com certeza demandará de mais processamento, lógicamente temos de levar em conta o que orientamos, tipo uma instrução:
For X = 1 To 10 só iremos executar 10 vezes ao passo se for : For X = 1 To 1000 o Loop irá até 1000.
É um assunto de fato complexo, como eu disse dependerá muito de testes e o que pretendemos.
Resumindo, sem contar que temos ainda "Loop (While, Until e Wend)", veja alguns exemplos:
VBA loops
http://www.learn.net.au/vba/vba-loops
Extrutura do Loop
http://doutorexcel.wordpress.com/2011/0 ... -wend-vba/
Using Loops in VBA in Microsoft Excel
http://www.exceltip.com/using-loops/usi ... excel.html
[]s
Existem mil maneiras de preparar Neston. Invente a sua!
http://www.youtube.com/ExpressoExcel
Obrigado pela resposta
o loop pode chegar a 1000000 de ciclos
já consegui diminuir os testes envolvidos com ajustes antes de entrar no loop reaproveitando as variáveis
o loop é esse com os de baixo, para evitar o uso de um monte de variáveis publicas usei o gosub
Do If Op = 0 Then GoSub OCoL: If T = 1 Then T = 0: GoSub OLin If Op = 1 Then GoSub OLin: If T = 1 Then T = 0: GoSub OCoL ffd = ffd + 1: Cells(Loi, Coi).Value = ffd '<<<<<adicionei apenas para testes da macro, vai ter mais instruções envolvidas Loop Until ffd = K GoTo Final
as diferenças são poucas pq os ajustes são feito antes de entrar no loop, tem muito mais coisas para entrar nesse montante.
OLin: If Op = 1 Then T = 0: Loi = Loi + Lig If OZig_L = False Then If Loi = OLf Then T = 1 If Oquadante_L = True Then GoSub OCoL: If T = 1 Then OLf = OLf + OqL: OLi = OLi + OqL: T = 0 Loi = OLi + Lig End If Else If Loi = OLi Or Loi = OLf Then T = 1 If Oquadante_L = True Then GoSub OCoL: If T = 1 Then OLf = OLf + OqL: OLi = OLi + OqL: T = 0: Loi = Loi + OqL Lig = Lig * -1: Loi = Loi + Lig End If End If End If Return OCoL: If Op = 1 Then If OZig_C = False Then If Coi = Ocf Then Coi = Oci + Zig: T = 1 End If Else If Coi = Oci Or Coi = Ocf Then Zig = Zig * -1: Coi = Coi + Zig: T = 1 End If End If End If Return
Tenho que juntar essa de baixo com a de cima e as outras que ainda vou fazer,
para chegar nesse ponto de simplicidade quase deu nó no cereblo
OLin: If Op = 0 Then If T = 1 Then Loi = Loi + Lig If OZig_L = False Then If Loi = OLf Then If Oquadante_L = True Then OLf = OLf + OqL: OLi = OLi + OqL Loi = OLi + Lig End If Else If Loi = OLi Or Loi = OLf Then If Oquadante_L = True Then OLf = OLf + OqL: OLi = OLi + OqL: Loi = Loi + OqL Lig = Lig * -1: Loi = Loi + Lig End If End If: End If Return OCoL: T = 0: Coi = Coi + Zig If Op = 0 Then If OZig_C = False Then If Coi = Ocf Then T = 1 GoSub OLin: Coi = Oci + Zig: End If Else If Coi = Oci Or Coi = Ocf Then T = 1 GoSub OLin: Zig = Zig * -1: Coi = Coi + Zig: End If End If End If Return
Até o momento está funcionando beleza, apesar de ter uma planilha salva com cada modificação
mas como vou adicionar mais rotinas nesse nó de raciocínio, pintou essa duvida sobre velocidade
Somente é impossíveis até que alguém faça
A logica está presa na irracionalidade humana, e morta nos que se consideram donos da verdade.
"ALGUM MODERADOR ME EXPULSE DO FÓRUM POR FAVOR"
só para simplificar e não ter que entender as linhas da rotina
inicialmente usei "DO Loop Until" pq o loop era até atingir certa condição,
agora vai ser um loop fixo determinado pela quantidade de dados.
será que um laço FOR NEXT é mais rápido ou dá na mesma?
perguntei sobre tamanho ou complexidade pq vai dobrar a quantidade de rotinas
pela analise que fiz:
fora os testes próprios de cada situação, somente terá um teste de entrada .
ficando 4 rotinas proprias, 1 teste de entrada e os testes principais
mas se juntar os processos, e usar mais testes para se alcançar a situação desejada,
teria que ser feito 6x mais testes fora os principais
ficando apenas 1 rotina, 6 testes de entrada e os testes principais
não sei se fui claro na pergunta
Somente é impossíveis até que alguém faça
A logica está presa na irracionalidade humana, e morta nos que se consideram donos da verdade.
"ALGUM MODERADOR ME EXPULSE DO FÓRUM POR FAVOR"
Edcronos, falar em Instruções : Do...Loop / While...Wend / For...Next, entre outras relacionadas, e dizer qual realmente é mais rápida sem ter de se analisar o código é um pouco vago na minha opinião devido as interações e a complexidade de cada elemento e resultado que estamos procurando.
Então sem analise nenhuma, pode-se dizer que o For...Next é mais rápido como pode ver na matéria abaixo :
Vamos acelerar nossos códigos - 3 - http://comunidade.itlab.com.br/eve/foru ... /577605361 no item :
FOR... NEXT é mais rápido que DO... LOOP :
Ainda que faça sentido, podemos não notar que o uso de DO... LOOP no lugar de FOR... NEXT é, geralmete, mais lento do que deveria. Cada passagem através de um DO... LOOP que itera um número específico de vezes exige que se incremente ou decremente algum tipo de contador do loop, enquanto que um loop FOR... NEXT faz isto automaticamente.
Por outro lado no link abaixo o Adilson mostra que um "For...Each...Next" é mais lento que um "With ActiveSheet.UsedRange", sei que você não citou estas instruções, coloquei mais para entendimento quando eu digo que depende do que fazemos, vai que com a definição de um For..Next é mais rápido e acabamos usando um "each" e aumentamos o tempo de processamento, tambem temos de ver que no exemplo citado pelo Adilson, ficou mais rápido quando utilizado com outro tipo de Metodo o: "SpecialCells ".
Então sugiro que faça a adaptação com o "For..Next" mas mantenha tambem a outra e realize aguns testes para conferir o tempo de processamento para o seu caso expecifico.
Na net tem vários outros links sobre o assunto, se encontrar algum mais interessante eu coloco, e tambem não esqueça de utilizar a própria ajuda do VBA, tem muita coisa interessante nela.
[]s
Existem mil maneiras de preparar Neston. Invente a sua!
http://www.youtube.com/ExpressoExcel
interessante a pagina, coisa que me surpreendeu foi o fato do byte ser mais lento q o long, sobre o Integer eu já tinha percebido.
agora essa parte de baixo apesar de eu já seguir a regra de dividir os testes do mais importante para o menos relevante , pensei que o vba pulasse questões que a primeira anulasse a segunda.
Dica: Também é interessante notar que o VBA não faz o curto circuíto das expressões lógicas AND e OR. Ou seja, em outras liguagens, quando temos um IF que inclui uma declaração OR composta (tipo "If x OR y Then"), ao se determinar que o primeiro operando é True, o código nem mesmo investiga o segundo argumento, a expressão toda é considerada verdadeira (True) (True OR QualquerExpressão é True, até mesmo True OR Null). Se escrevermos uma declaração composta AND (ou seja "If x AND y Then"), ao se determinar que o primeiro operando é False, o código nem investiga o segundo argumento e a expressão toda é considerada False (Falso e QualquerExpressão é Falso, até mesmo False AND Null). Não podemos contar com este comportamento no VBA para evitar erros de execução, já que ele não acontece e o VBA vai SEMPRE avaliar ambas as operações em qualquer expressão antes de determinar o resultado.
As dicas são de 2003, será que todas elas ainda são validas nas atuais versões do VBA?
Se ainda é valido o topico está resolvido, e o melhor é manter código extenso mas com poucos testes de entrada do que comprimido e muitos testes para validar "ainda mais em um loop que pode chegar a 1000000 de ciclos"
Tem muitas coisas que reparei nos meus testes,
alteração de valores quando são muitos dados , o melhor é fazer numa área que não tenha formatação ou formulas
mesmo com Application.ScreenUpdating = False e Application.Calculation = xlCalculationManual se forem muitos dados o processo pode se tornar moroso. eu uso uma area auxiliar.
vba lida melhor com linhas do que com colunas é mais rápido gravar "célula por célula" 10.000 linhas x 3 colunas do que 1000 colunas x 3 linhas, pelo menos nos meus testes a diferença de tempo foram bem grandes
Somente é impossíveis até que alguém faça
A logica está presa na irracionalidade humana, e morta nos que se consideram donos da verdade.
"ALGUM MODERADOR ME EXPULSE DO FÓRUM POR FAVOR"
acho q o segundo link nao apareceu
Por outro lado no link abaixo o Adilson mostra que um "For...Each...Next" é mais lento que um "With ActiveSheet.UsedRange", sei que você não citou estas instruções, coloquei mais para entendimento quando eu digo que depende do que fazemos, vai que com a definição de um For..Next é mais rápido e acabamos usando um "each" e aumentamos o tempo de processamento, tambem temos de ver que no exemplo citado pelo Adilson, ficou mais rápido quando utilizado com outro tipo de Metodo o: "SpecialCells ".
Somente é impossíveis até que alguém faça
A logica está presa na irracionalidade humana, e morta nos que se consideram donos da verdade.
"ALGUM MODERADOR ME EXPULSE DO FÓRUM POR FAVOR"
acho q o segundo link nao apareceu
Por outro lado no link abaixo o Adilson mostra que um "For...Each...Next" é mais lento que um "With ActiveSheet.UsedRange", sei que você não citou estas instruções, coloquei mais para entendimento quando eu digo que depende do que fazemos, vai que com a definição de um For..Next é mais rápido e acabamos usando um "each" e aumentamos o tempo de processamento, tambem temos de ver que no exemplo citado pelo Adilson, ficou mais rápido quando utilizado com outro tipo de Metodo o: "SpecialCells ".
Ops, já estava quase dormindo, rsrsrsrrs
Segue o link:
0166-Dica VBA: Método SpecialCells
http://usuariosdoexcel.wordpress.com/20 ... cialcells/
[]s
Existem mil maneiras de preparar Neston. Invente a sua!
http://www.youtube.com/ExpressoExcel
Valeu,
já tinha lido a respeito, até hoje usei pouco por causa de meus projetos que são em cima de uma mesma planilha.
nesse caso o loop é célula por célula indecente de "valores" que podem ter até espaços em branco.
mas me diga,
As dicas do primeiro link são de 2003, será que todas elas ainda são validas na atual versão do VBA office 2010
se ainda valerem as regras, minhas perguntas estão respondidas.
Somente é impossíveis até que alguém faça
A logica está presa na irracionalidade humana, e morta nos que se consideram donos da verdade.
"ALGUM MODERADOR ME EXPULSE DO FÓRUM POR FAVOR"
"As dicas são de 2003, será que todas elas ainda são validas nas atuais versões do VBA?"
Infelizmente, a Microsoft não faz uma atualização significativa desde 1999, então sim, esse tipo de dica ainda vale hoje para o VBA.
"interessante a pagina, coisa que me surpreendeu foi o fato do byte ser mais lento q o long, sobre o Integer eu já tinha percebido."
Eu sempre desconfiei que o motivo do tipo de dados Long ser mais rápido fosse por esse motivo: http://www.ambienteoffice.com.br/officevba/tipos_de_dados/#usar_ou_nao_usar_integer?
Felipe Costa Gualberto
Microsoft Excel MVP
http://www.ambienteoffice.com.br
então para concluir...
se o loop for fixo um "For Next"
iF:
em vez de "if y AND X or F or g then.." usar "if y then: if x or f or g then..." para assim fazer apenas os outros testes se passar no primeiro.
variáveis:Long sempre,
Byte somente em arrays mesmo pq a memoria alocada não vai ser dividida com outros dados ,
Integer deixa mais lento "já tinha percebido em testes, com long foi instantâneo e com intenger levou 1s".
E as dicas de minha parte:
alteração de valores quando são muitos dados , o melhor é fazer numa área que não tenha formatação ou formulas
mesmo com
Application.ScreenUpdating = False e Application.Calculation = xlCalculationManual
Se forem muitos dados o processo pode se tornar moroso. eu uso uma area auxiliar para tais processos
Essa macro de baixo, quando não tem formatação e formulas é praticamente instantânea,
quando tem, dependendo, melhor é ir alongar as pernas dando um passeio com o cachorro.
Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Limpa Plan_Ori = Plan_Princ Plan_C_Ref = Plan_Princ LR = Sheets(Plan_Ori).Cells(Rows.Count, CData).End(xlUp).Row For Each rngO In Sheets(Plan_Ori).Range((CData & Li), (CData & LR)) If rngO.Value <> "" Then Set rngD = Sheets(Plan_C_Ref).[C:C].Find(rngO) If Not rngD Is Nothing Then Range(Ti & rngD.Row, Cf & rngD.Row) = Sheets(Plan_Ori).Range(Ti & rngO.Row, Cf & rngO.Row).Value End If End If Next rngO Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True
repara não, minhas macros são todas assim, com variáveis. essa de cima ainda tenho que adicionar as linhas para uso de area aux.
vba lida melhor com linhas do que com colunas é mais rápido gravar "célula por célula" 10.000 linhas x 3 colunas do que 1000 colunas x 3 linhas, pelo menos nos meus testes a diferença de tempo foram bem grandes
Somente é impossíveis até que alguém faça
A logica está presa na irracionalidade humana, e morta nos que se consideram donos da verdade.
"ALGUM MODERADOR ME EXPULSE DO FÓRUM POR FAVOR"
Seria bom adicionar um DoEvents para não congelar o Excel enquanto a macro executa:
'...código... lngDoEvents = lngDoEvents + 1 If lngDoEvents Mod 1000 = 0 Then DoEvents Next rngO
Além disso, use a instrução Option Explicit na seção de declaração do seu módulo. Você terá ganhos em velocidade.
Option Explicit Sub pMain() Dim lngDoEvents As Long Dim Plan_Ori As String Dim Plan_Princ As String Dim Plan_C_Ref As String Dim CData As String Dim LR As Long Dim Li As Long Dim rngO As Excel.Range Dim rngD As Excel.Range Dim Ti As String Dim Cf As String '...código...
Prefira utilizar a propriedade Value2 do objeto Range ao invés de Value.
Range(Ti & rngD.Row, Cf & rngD.Row).Value2 = Sheets(Plan_Ori).Range(Ti & rngO.Row, Cf & rngO.Row).Value2
Intervalos entre colchetes são mais lentos que sua representação através do objeto Columns:
Set rngD = Sheets(Plan_C_Ref).Columns("C").Find(rngO)
Desconfio que é possível melhorar o código abaixo:
For Each rngO In Sheets(Plan_Ori).Range((CData & Li), (CData & LR)) If rngO.Value <> "" Then '...instruções... End If Next rngO
troque para:
Dim rngUsed As Excel.Range Dim rngConstants As Excel.Range Dim rngFormulas As Excel.Range With Sheets(Plan_Ori).Range((CData & Li), (CData & LR)) Set rngUsed = .Parent.UsedRange Set rngConstants = .SpecialCells(xlCellTypeConstants) Set rngFormulas = .SpecialCells(xlCellTypeFormulas) Set rngUsed = Intersect(rngUsed, Union(rngConstants, rngFormulas)) End With For Each rngO In rngUsed '...instruções... Next rngO
Nota: para o código acima funcionar, deverá haver pelo menos uma célula com fórmula e uma célula com uma constante no intervalo Sheets(Plan_Ori).Range((CData & Li), (CData & LR))
Felipe Costa Gualberto
Microsoft Excel MVP
http://www.ambienteoffice.com.br
Além disso, use a instrução Option Explicit na seção de declaração do seu módulo. Você terá ganhos em velocidade.
as variáveis são publicas e utilizadas por todas as macros com o mesmo propósito
a macro que estou atualmente trabalhando tem essas variáveis para o loop, fora as publicas e as de controle
'Dim ns As Byte Dim Ddo As Variant, ddai As Long '----------------------Dados Dim Tv As Long ' ---------------------------------------Teste de Valores 1 = passa no teste : 0 = Não passa Dim T As Long '-----------------------------------Teste de teste 0 = Negativo : 1 = Positivo Dim K As Long, F As Long ''-----------------------------------( ORIGEM )----------------------------------------------------------- Dim Op As Long '--------------------------------------Direção prioritária DA ORIGEM 0 = coluna: 1 = Linha Dim OLi As Long, OLf As Long, TLo As Long '-------------------------Linha inicial e final,Total linhas da origem Dim Oci As Long, Ocf As Long '---------------------------------Coluna inicial e Final Dim Coi As Long, Loi As Long ' ---------------------------Posição Coluna origem Dim Zig As Long, Lig As Long '----------------------incremento de Coluna e Linha Dim OqC As Long, OqL As Long '--------------quantidade de Colunas e Linhas do quadrante Dim OqLi As Long, OqLf As Long '---------Linha inicial e final do quadrante Dim OqCi As Long, OqCf As Long '------Coluna inicial e final do quadrante '---------------------------------( DESTINO )----------------------------------------------- Dim Dp As Byte '-----------------------------------------------------Direção prioritária do Destino 0 = coluna: 1 = Linha Dim DLi As Long, DLf As Long, TLd As Long '---------------------------------Linha inicial e final,Total linhas do Destino Dim Dci As Long, Dcf As Long '--------------------------------------------Coluna inicial e Final Dim Cdi As Long, Ldi As Long ' ------------------------------------Posição Coluna Destino Dim Zag As Long, Lag As Long '--------------------------------incremento de Coluna e Linha Dim DqC As Long, DqL As Long '-------------------------quantidade de Colunas e Linhas do quadrante Dim DqLi As Long, DqLf As Long '------------------Linha inicial e final do quadrante Dim DqCi As Long, DqCf As Long '-------------Coluna inicial e final do quadrante
Seria bom adicionar um DoEvents para não congelar o Excel enquanto a macro executa:
eu teria que entender melhor para ver a aplicação e oq exatamente faz o código
o mesmo com Application.EnableEvents = False e Application.EnableEvents = True
Prefira utilizar a propriedade Value2 do objeto Range ao invés de Value.
já tinha visto sobre isso, mas não entendi a questão do VALUE e VALUE2
Intervalos entre colchetes são mais lentos que sua representação através do objeto Columns:
Nem uso assim, essa foi uma adaptação de uma macro na epoca que estava começando a aprender VBA
http://forum.baboo.com.br/index.php?/topic/770419-copiar-valores-de-posi%C3%A7%C3%B5es-definidas-por-variaveis-e-colar-na-mesma-linha-com-data-igual-ao-da-coluna-c/
Desconfio que é possível melhorar o código abaixo:
não tem formulas nesse intervalo,
A macro pega os valores do setor e coloca nas mesmas linhas das datas da coluna B,
a coluna de data do setor é definida por CData
essa macro uso muito pouco e é acionada antes de entrar as formatações na planilha então larguei um pouco de lado.
Somente é impossíveis até que alguém faça
A logica está presa na irracionalidade humana, e morta nos que se consideram donos da verdade.
"ALGUM MODERADOR ME EXPULSE DO FÓRUM POR FAVOR"
sobre value e value2 já entendi e obrigado, vai me ajudar nessa macro que estou escrevendo.
value tenta transferir tbm o formato de data e moeda, não apenas o valor.
"agora entendi as zicas que dava nas celulas nos testes quando a macro pegava valor fora de area"
Somente é impossíveis até que alguém faça
A logica está presa na irracionalidade humana, e morta nos que se consideram donos da verdade.
"ALGUM MODERADOR ME EXPULSE DO FÓRUM POR FAVOR"
Ótimas práticas. Mais alguns pensamentos:
as variáveis são publicas e utilizadas por todas as macros com o mesmo propósito
Na verdade, você utilizou variáveis de nível de módulo, e isso é melhor que utilizar variáveis públicas no que se trata de desempenho. Só não podemos esquecer de reiniciar os valores dessas variáveis a cada nova execução do procedimento pai para que elas não retenham valores da execução anterior e gerem erros em suas subrotinas.
já tinha visto sobre isso, mas não entendi a questão do VALUE e VALUE2
Value possui um overhead maior porque verifica se o tipo de formatação da célula é moeda ou data.
Value trunca o valor real de uma célula em duas casas decimais no caso de ela estar formatada como moeda.
Atribuir o valor de uma célula com um tipo de dados de moeda ou data altera sua formatação de exibição para um desses formatos.
Value2, além de não ter esse overhead, sempre retorna/atribui números de séries de datas (ao invés de, por exemplo, dd/mm/aaaa) e não trunca valores formatados com tipo de dados de moeda.
não tem formulas nesse intervalo
Basta trocar para:
Dim rngConstants As Excel.Range With Sheets(Plan_Ori).Range((CData & Li), (CData & LR)) Set rngUsed = .Parent.UsedRange Set rngConstants = .SpecialCells(xlCellTypeConstants) Set rngUsed = Intersect(rngUsed, rngFormulas) End With For Each rngO In rngUsed '...instruções... Next rngO
essa macro uso muito pouco e é acionada antes de entrar as formatações na planilha então larguei um pouco de lado.
Sim, não estamos aqui para transformar seu código no mais eficiente do mundo. Por exemplo: os códigos que escrevo para uso pessoal no meu dia-a-dia são sofríveis, tenho até vergonha de mostrar. Estamos somente pegando alguns pontos de melhoria de desempenho num pequeno código que achei que ilustra muito bem esse estudo de caso, que poderá servir de auxílio para o pessoal que está acompanhando o tópico.
Felipe Costa Gualberto
Microsoft Excel MVP
http://www.ambienteoffice.com.br