Uma mudança de hoje: FOR EACH

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Uma mudança de hoje: FOR EACH

Mensagem por JoséQuintas »

Alterei uma rotina pra FOR EACH, e na hora de decidir se simplifiquei ou não, só sobrou rir... rs
Gostei principalmente dos GETs, eliminando problemas com array
calculo.png
Na parte de cima são extratos pra pagamento
Na parte de baixo são cheques emitidos

A intenção é mostrar em cada extrato, quanto os cheques causaram de baixa, e qual o saldo restante.

antes da alteração

Código: Selecionar todos

CREATE CLASS CalculaBaixaExtratoClass
   VAR mExtrato
   VAR mBaixa
   VAR mSaldo
   VAR mCheque
   VAR mTexto       INIT Space(50)
   VAR mSomaExtrato INIT 0
   VAR mSomaBaixa   INIT 0
   VAR mSomaSaldo   INIT 0
   VAR mSomaCheque  INIT 0
   VAR mSaldoCheque INIT 0
   METHOD Init()
   METHOD Calcula()
   END CLASS

METHOD Init() CLASS CalculaBaixaExtratoClass
   ::mExtrato := Array(10)
   ::mBaixa   := Array(10)
   ::mSaldo   := Array(10)
   ::mCheque  := Array(10)
   Afill( ::mExtrato, 0 )
   Afill( ::mBaixa, 0 )
   Afill( ::mSaldo, 0 )
   Afill( ::mCheque, 0 )
   RETURN SELF

METHOD Calcula() CLASS CalculaBaixaExtratoClass

   LOCAL mTotal := 0, nCont

   FOR nCont = 1 TO 10
      mTotal += ::mCheque[ nCont ]
   NEXT
   FOR nCont = 1 TO 10
      IF ::mExtrato[ nCont ] == mTotal
         ::mBaixa[ nCont ] := mTotal
         ::mSaldo[ nCont ] := 0
         mTotal          := 0
      ELSEIF ::mExtrato[ nCont ] > mTotal
         ::mBaixa[ nCont ] := mTotal
         ::mSaldo[ nCont ] := ::mExtrato[ nCont ] - ::mBaixa[nCont ]
         mTotal          := 0
      ELSE
         ::mBaixa[ nCont ] := ::mExtrato[ nCont ]
         ::mSaldo[ nCont ] := 0
         mTotal -= ::mBaixa[ nCont ]
      ENDIF
   NEXT
   ::mSomaExtrato := 0
   ::mSomaBaixa   := 0
   ::mSomaCheque  := 0
   ::mSomaSaldo   := 0
   FOR nCont = 1 TO Len( ::mExtrato )
      ::mSomaExtrato += ::mExtrato[ nCont ]
      ::mSomaBaixa   += ::mBaixa[ nCont ]
      ::mSomaSaldo   += ::mSaldo[ nCont ]
      ::mSomaCheque  += ::mCheque[ nCont ]
   NEXT
   ::mSaldoCheque := ::mSomaCheque - ::mSomaBaixa

   IF ::mSaldoCheque != 0
      ::mTexto := Pad( "FALTA OU SOBRA VALOR DE CHEQUE", 50 )
   ELSE
      ::mTexto := Space(50)
   ENDIF
   RETURN .T.

FUNCTION CalculaBaixaExtrato()

   LOCAL GetList := {}, oVal := CalculaBaixaExtratoClass():New()

   wSave()
   Cls()
   @ 2, 1              SAY "Valor extrato 1.:" GET oVal:mExtrato[ 1 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row(), Col() + 2  SAY "Baixar:"           GET oVal:mBaixa[ 1 ]   PICTURE "999,999,999.99" WHEN .F.
   @ Row(), Col() + 2  SAY "Saldo:"            GET oVal:mSaldo[ 1 ]   PICTURE "999,999,999.99" WHEN .F.
   @ Row() + 1, 1      SAY "Valor extrato 2.:" GET oVal:mExtrato[ 2 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row(), Col() + 2  SAY "Baixar:"           GET oVal:mBaixa[ 2 ]   PICTURE "999,999,999.99" WHEN .F.
   @ Row(), Col() + 2  SAY "Saldo:"            GET oVal:mSaldo[ 2 ]   PICTURE "999,999,999.99" WHEN .F.
   @ Row() + 1, 1      SAY "Valor extrato 3.:" GET oVal:mExtrato[ 3 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row(), Col() + 2  SAY "Baixar:"           GET oVal:mBaixa[ 3 ]   PICTURE "999,999,999.99" WHEN .F.
   @ Row(), Col() + 2  SAY "Saldo:"            GET oVal:mSaldo[ 3 ]   PICTURE "999,999,999.99" WHEN .F.
   @ Row() + 1, 1      SAY "Valor extrato 4.:" GET oVal:mExtrato[ 4 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row(), Col() + 2  SAY "Baixar:"           GET oVal:mBaixa[ 4 ]   PICTURE "999,999,999.99" WHEN .F.
   @ Row(), Col() + 2  SAY "Saldo:"            GET oVal:mSaldo[ 4 ]   PICTURE "999,999,999.99" WHEN .F.
   @ Row() + 1, 1      SAY "Valor extrato 5.:" GET oVal:mExtrato[ 5 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row(), Col() + 2  SAY "Baixar:"           GET oVal:mBaixa[ 5 ]   PICTURE "999,999,999.99" WHEN .F.
   @ Row(), Col() + 2  SAY "Saldo:"            GET oVal:mSaldo[ 5 ]   PICTURE "999,999,999.99" WHEN .F.
   @ Row() + 2, 1      SAY "Somas"
   @ Row(), Col() + 13 GET oVal:mSomaExtrato PICTURE "999,999,999.99" WHEN .F.
   @ Row(), Col() + 10 GET oVal:mSomaBaixa   PICTURE "999,999,999.99" WHEN .F.
   @ Row(), Col() + 9  GET oVal:mSomaSaldo   PICTURE "999,999,999.99" WHEN .F.
   @ Row() + 2, 1      SAY "Cheque 1........:" GET oVal:mCheque[ 1 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row() + 1, 1      SAY "Cheque 2........:" GET oVal:mCheque[ 2 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row() + 1, 1      SAY "Cheque 3........:" GET oVal:mCheque[ 3 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row() + 1, 1      SAY "Cheque 4........:" GET oVal:mCheque[ 4 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row() + 1, 1      SAY "Cheque 5........:" GET oVal:mCheque[ 5 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row() + 1, 1      SAY "Cheque 6........:" GET oVal:mCheque[ 6 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row() + 1, 1      SAY "Cheque 7........:" GET oVal:mCheque[ 7 ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   @ Row() + 2, 5      SAY "Soma Cheque:"      GET oVal:mSomaCheque  PICTURE "999,999,999.99" WHEN .F.
   @ Row(), Col() + 3  SAY "Saldo em cheque:"  GET oVal:mSaldoCheque PICTURE "999,999,999.99" WHEN .F.
   @ Row() + 2, 20 GET oVal:mTexto WHEN .F.
   READ
   wRestore()
   RETURN NIL
depois da alteração

Código: Selecionar todos

#define V_EXTRATO 1
#define V_BAIXA   2
#define V_SALDO   3
#define V_CHEQUE  4

CREATE CLASS CalculaBaixaExtratoClass
   VAR mLancto
   VAR mSoma        INIT { 0, 0, 0, 0 }
   VAR mTexto       INIT Space(50)
   METHOD Init()
   METHOD Calcula()
   END CLASS

METHOD Init() CLASS CalculaBaixaExtratoClass

   LOCAL oElement

   ::mLancto := Array(10)
   FOR EACH oElement IN ::mLancto
      oElement := { 0, 0, 0, 0 }
   NEXT
   RETURN SELF

METHOD Calcula() CLASS CalculaBaixaExtratoClass

   LOCAL mTotal := 0, oElement

   FOR EACH oElement IN ::mLancto
      mTotal += oElement[ V_CHEQUE ]
   NEXT
   FOR EACH oElement IN ::mLancto
      IF oElement[ V_EXTRATO ] == mTotal
         oElement[ V_BAIXA ] := mTotal
         oElement[ V_SALDO ] := 0
         mTotal              := 0
      ELSEIF oElement[ V_EXTRATO ] > mTotal
         oElement[ V_BAIXA ] := mTotal
         oElement[ V_SALDO ] := oElement[ V_EXTRATO ] - oElement[ V_BAIXA ]
         mTotal              := 0
      ELSE
         oElement[ V_BAIXA ] := oElement[ V_EXTRATO ]
         oElement[ V_SALDO ] := 0
         mTotal -= oElement[ V_BAIXA ]
      ENDIF
   NEXT
   ::mSoma := { 0, 0, 0, 0 }
   FOR EACH oElement IN ::mLancto
      ::mSoma[ V_EXTRATO ] += oElement[ V_EXTRATO ]
      ::mSoma[ V_BAIXA   ] += oElement[ V_BAIXA   ]
      ::mSoma[ V_CHEQUE  ] += oElement[ V_CHEQUE  ]
      ::mSoma[ V_SALDO   ] += oElement[ V_SALDO   ]
   NEXT
   ::mSoma[ V_SALDO ] := ::mSoma[ V_CHEQUE ] - ::mSoma[ V_BAIXA ]

   IF ::mSoma[ V_SALDO ] != 0
      ::mTexto := Pad( "FALTA OU SOBRA VALOR DE CHEQUE", 50 )
   ELSE
      ::mTexto := Space(50)
   ENDIF
   RETURN .T.

FUNCTION CalculaBaixaExtrato()

   LOCAL GetList := {}, oElement, oVal := CalculaBaixaExtratoClass():New()

   wSave()
   Cls()
   @ 1, 0 SAY ""
   FOR EACH oElement IN oVal:mLancto
      @ Row() + 1, 1      SAY "Valor extrato:" GET oElement[ V_EXTRATO ] PICTURE "999,999,999.99" VALID oVal:Calcula()
      @ Row(), Col() + 2  SAY "Baixar:"        GET oElement[ V_BAIXA   ] PICTURE "999,999,999.99" WHEN .F.
      @ Row(), Col() + 2  SAY "Saldo:"         GET oElement[ V_SALDO   ] PICTURE "999,999,999.99" WHEN .F.
   NEXT
   @ Row() + 2, 1         SAY "Somas"
   @ Row(), Col() + 10    GET oVal:mSoma[ V_EXTRATO ] PICTURE "999,999,999.99" WHEN .F.
   @ Row(), Col() + 10    GET oVal:mSoma[ V_BAIXA   ] PICTURE "999,999,999.99" WHEN .F.
   @ Row(), Col() + 9     GET oVal:mSoma[ V_SALDO   ] PICTURE "999,999,999.99" WHEN .F.
   @ Row() + 1, 0         SAY ""
   FOR EACH oElement IN oVal:mLancto
      @ Row() + 1, 1      SAY "Cheque .........:" GET oElement[ V_CHEQUE ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   NEXT
   @ Row() + 2, 5      SAY "Soma Cheque:"      GET oVal:mSoma[ V_CHEQUE ] PICTURE "999,999,999.99" WHEN .F.
   @ Row(), Col() + 3  SAY "Saldo em cheque:"  GET oVal:mSoma[ V_SALDO  ] PICTURE "999,999,999.99" WHEN .F.
   @ Row() + 2, 20 GET oVal:mTexto WHEN .F.
   READ
   wRestore()
   RETURN NIL
Nota:
Aqui funcionou, mas cai naquilo da minha GETSYS atualizar os GETs automaticamente, afinal toda tela é atualizada durante a digitação.
Pra ficar igual, teria que passar GetList como parâmetro nos VALID, e na rotina de cálculo fazer o get:Display() pra toda GetList.
Mas a intenção é mostrar a mudança do fonte usando FOR EACH.
É um fonte totalmente fora do normal.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Uma mudança de hoje: FOR EACH

Mensagem por JoséQuintas »

Destaque:

FOR EACH pra atribuir valores e pra GETs... achei muito legal.
Nesta parte, atribui valor pra cada elemento do array

Código: Selecionar todos

mLancto := Array(10)
FOR EACH oElement IN mLancto
   oElement := { 0, 0, 0, 0 }
NEXT
Nesta parte, GET pra cada elemento do array

Código: Selecionar todos

   FOR EACH oElement IN oVal:mLancto
      @ Row() + 1, 1      SAY "Cheque .........:" GET oElement[ V_CHEQUE ] PICTURE "999,999,999.99" VALID oVal:Calcula()
   NEXT
Mas ficou sem o contador pro texto (cheque 1,2,3,4...)
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Uma mudança de hoje: FOR EACH

Mensagem por JoséQuintas »

Esqueci de mencionar:
Antes da alteração eram 5 extratos e 7 cheques.
Agora são 10 de cada.
No final, agora tem 18 GETs a mais. (em cada extrato são 3 GETs.)

Por causa do FOR EACH, agora o limite é apenas a tela. Basta definir o tamanho do array, e não precisa alterar mais nada no fonte.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
microvolution
Usuário Nível 5
Usuário Nível 5
Mensagens: 1231
Registrado em: 02 Set 2011 22:17
Contato:

Uma mudança de hoje: FOR EACH

Mensagem por microvolution »

professor, boa noite!
você só posta "trem chick no úrtimo" no qual percebo que estou "anos luz" atrás de V.Sas.
Enquanto que para você é como "soltar pipa", pra mim é como "não saber andar de bicicleta (nunca ter andado)" e já querer começar "andando já de uma roda"!!! :%
Tenho que me reciclar mesmo... afinal, fiquei muitos anos com um mesmo código (apesar de ser muito bem funcional) mas, ultrapassadérrimo!
ah! nem sei o que é FOR EACH!!!
:-O
mais uma vez, parabéns!
Grato,
MICROVOLUTION - 16 anos Evoluindo Com Você!


Você já leu a Bíblia hoje?
João 3:16 - Porque Deus amou ao mundo de tal maneira que deu seu Único Filho para que todo aquele que nEle crê não pereça mas tenha a Vida Eterna!
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Uma mudança de hoje: FOR EACH

Mensagem por JoséQuintas »

É só olhar a classe pensando num programa normal com variáveis públicas.
O que é METHOD, considerar FUNCTION.


Simplificando sobre o FOR EACH: Compare:

Código: Selecionar todos

FOR nCont = 1 TO Len( SalaDeAula )
   PuxaOrelha( SalaDeAula[ nCont ] )
NEXT

Código: Selecionar todos

FOR EACH Aluno IN SalaDeAula
   PuxaOrelha( Aluno )
NEXT
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
fladimir
Colaborador
Colaborador
Mensagens: 2445
Registrado em: 15 Nov 2006 20:21

Uma mudança de hoje: FOR EACH

Mensagem por fladimir »

Essa explicação com Aluno e Sala de Aula matou a pau...

:-Y :{
Sun Tzu há mais de três mil anos cita nas epígrafes de seu livro “A Arte da Guerra“:

“Concentre-se nos pontos fortes, reconheça as fraquezas, agarre as oportunidades e proteja-se contra as ameaças”.
“Se não é vantajoso, nunca envie suas tropas; se não lhe rende ganhos, nunca utilize seus homens; se não é uma situação perigosa, nunca lute uma batalha precipitada”
.


Até 2017    Desktop Console [ Legado ] Harbour | MinGW | DBF | CDX | FastReport | MySQL


Novos Projetos:

   Desktop Visual           Windev Desktop
   Celular Android/iOS   Windev Mobile
   WEB                            Windev Web


Sejamos gratos a Deus.
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Uma mudança de hoje: FOR EACH

Mensagem por JoséQuintas »

Veio como inspiração durante o post, e mostra exatamente a mudança do FOR EACH no fonte.

Acaba ficando bem claro o que está sendo tratado dentro do bloco.
E nem precisa saber quantos são, ou qual o número de cada um, basta saber que vai ser feito pra todos.

Se reparar direito, com FOR/NEXT nem dá pra saber do que se trata, ele é que tá mais difícil de entender.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
fladimir
Colaborador
Colaborador
Mensagens: 2445
Registrado em: 15 Nov 2006 20:21

Uma mudança de hoje: FOR EACH

Mensagem por fladimir »

Como simplificar a rotina abaixo com FOR... EACH ?

Ela esta funcionando (falta alguns detalhes mas a ideia central esta ok)... Exemplo o cliente faz N orçamentos para Y Clientes e cada cliente pode ser de 1 cidade... preciso gerar um relatório com os produtos agrupados por cidade independente do cliente...

Da forma abaixo (ainda não finalizada) esta gerando um Array muldimensional com as cidades e os produtos agrupados por cidade

Código: Selecionar todos


... Rotina q gera relatorio
	local aCidades, nPosCidade, TT 

	aCidades := {}
	while Orcam->(!EOF())
		
		if Clientes->( dbseek(Orcam->CodCli) )
			cCidade := Clientes->Cidade
		else
			cCidade := padc('NAO LOCALIZADA', 25)
		endif

		nPosCidade := 0
		TT := 1
		if empty(aCidades)
	      aadd(aCidades, { cCidade, { {'', '', 0, 0, 0} } } ) 
	      nPosCidade := 1

	   else
	      lNao_e_Igual := .T.
	      for TT:= 1 TO LEN(aCidades)      
	         if aCidades[TT,1] == cCidade  
	            lNao_e_Igual := .F.
					nPosCidade := TT
	            EXIT
	         endif
	      next
	
	      if lNao_e_Igual                      &&-- SE a VARREDURA nao encontrou NADA / Ai adiciona
	      	aadd(aCidades, { cCidade, { {'', '', 0, 0, 0} } } ) 
				nPosCidade := len(aCidades)		         
	      endif
	   endif
		Vequestaodosprodutosnessacidade(@aCidades, nPosCidade)
		Orcam->(dbskip())
	end

//--> no final tenho um Array com as cidades e cada cidade com seus produtos agrupados 
...



static function Vequestaodosprodutosnessacidade(aCidades, nPosCidade)
	local nI, aProdutosCid, lNotEqual

	aProdutosCid := aCidades[nPosCidade][2] && array dos produtos

   lNotEqual := .T.
   for nI:= 1 TO LEN(aProdutosCid)             
      if aProdutosCid[nI][1] == Orcam->CodProd         //-- se encontrar igualdade cai fora
			aCidades[nPosCidade][2][nI][3] += Orcam->QTDE
			aCidades[nPosCidade][2][nI][4] += Orcam->vl_total
         lNotEqual := .F.
         EXIT
      endif
   next

   if lNotEqual                      //-- SE a VARREDURA nao encontrou NADA / Ai adiciona
      aadd(aCidades[nPosCidade][2], { Orcam->CodProd,;
												  Orcam->descricao,;
												  Orcam->qtde,;
												  Orcam->vl_total,;
												  Produto->Estoque  } )
   endif
return
Sun Tzu há mais de três mil anos cita nas epígrafes de seu livro “A Arte da Guerra“:

“Concentre-se nos pontos fortes, reconheça as fraquezas, agarre as oportunidades e proteja-se contra as ameaças”.
“Se não é vantajoso, nunca envie suas tropas; se não lhe rende ganhos, nunca utilize seus homens; se não é uma situação perigosa, nunca lute uma batalha precipitada”
.


Até 2017    Desktop Console [ Legado ] Harbour | MinGW | DBF | CDX | FastReport | MySQL


Novos Projetos:

   Desktop Visual           Windev Desktop
   Celular Android/iOS   Windev Mobile
   WEB                            Windev Web


Sejamos gratos a Deus.
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Uma mudança de hoje: FOR EACH

Mensagem por JoséQuintas »

Acho que está vendo do modo errado.
Não precisa nem FOR EACH e nem FOR NEXT.
Direto no post, sem testar, mais ou menos isto:

Código: Selecionar todos

... Rotina q gera relatorio
 local aCidades, nPosCidade, TT 

 aCidades := {}
 while Orcam->(!EOF())
  
  if Clientes->( dbseek(Orcam->CodCli) )
   cCidade := Clientes->Cidade
  else
   cCidade := padc('NAO LOCALIZADA', 25)
  endif

  nPosCidade := AScan( aCidades, { | oElemento | oElemento[ 1 ] == cCidade } )
   IF nPosCidade == 0
      aadd(aCidades, { cCidade, {} )
     nPosCidade := Len( aCidades )
ENDIF
  Vequestaodosprodutosnessacidade(@aCidades[ nPosCidade ] [ 2 ] )
  Orcam->(dbskip())
 end

//--> no final tenho um Array com as cidades e cada cidade com seus produtos agrupados 
...

static function Vequestaodosprodutosnessacidade( aProdutos )

LOCAL nPosProduto

nPosProduto := AScan(  aProdutos, { | oElemento | oElemento[ 1 ] == orcam->CodProd } )
IF nPosProduto == 0
   AAdd( aProdutos, { orcam->CodProd, orcam->Descricao, 0, 0, produto->Estoque } )
   nPosProduto := Len( aProdutos )
ENDIF
aProdutos[ nPosProduto ][3] += Orcam->QTDE
aProdutos[ nPosProduto ][4] += Orcam->vl_total
return
Mas considerando que deve ordenar depois, eu criaria um arquivo temporário pra isso.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
fladimir
Colaborador
Colaborador
Mensagens: 2445
Registrado em: 15 Nov 2006 20:21

Uma mudança de hoje: FOR EACH

Mensagem por fladimir »

Vlw Quintas.
Sun Tzu há mais de três mil anos cita nas epígrafes de seu livro “A Arte da Guerra“:

“Concentre-se nos pontos fortes, reconheça as fraquezas, agarre as oportunidades e proteja-se contra as ameaças”.
“Se não é vantajoso, nunca envie suas tropas; se não lhe rende ganhos, nunca utilize seus homens; se não é uma situação perigosa, nunca lute uma batalha precipitada”
.


Até 2017    Desktop Console [ Legado ] Harbour | MinGW | DBF | CDX | FastReport | MySQL


Novos Projetos:

   Desktop Visual           Windev Desktop
   Celular Android/iOS   Windev Mobile
   WEB                            Windev Web


Sejamos gratos a Deus.
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Uma mudança de hoje: FOR EACH

Mensagem por JoséQuintas »

Já passei algumas vezes neste tópico, e sempre dá vontade de melhorar mais um pouquinho.
Então postar de vez, assim acaba com a vontade... rs

Dá pra aplicar a mesma regra nos dois casos.

Código: Selecionar todos

   LOCAL aCidades, nPosCidade

   aCidades := {}
   DO WHILE Orcam->( ! Eof() )
       IF Clientes->( dbseek( Orcam->CodCli ) )
          cCidade := Clientes->Cidade
      ELSE
         cCidade := padc( 'NAO LOCALIZADA', 25 )
      ENDIF
      AcumulaCidade( aCidades, cCidade )
      SKIP
   ENDDO

   RETURN

STATIC FUNCTION AcumulaCidade( aCidades, cCidade )

   LOCAL nPos

   nPos := AScan( aCidades, { | oElemento | oElemento[ 1 ] == cCidade } )
   IF nPos == 0
      aadd(aCidades, { cCidade, {} )
      nPos := Len( aCidades )
   ENDIF
   AcumulaProduto( aCidades[ nPos, 2 ] )

   RETURN NIL

STATIC FUNCTION AcumulaProduto( aProdutos )

   LOCAL nPos

   nPos := AScan( aProdutos, { | oElemento | oElemento[ 1 ] == orcam->CodProd } )
   IF nPos == 0
      AAdd( aProdutos, { orcam->CodProd, orcam->Descricao, 0, 0, produto->Estoque } )
      nPos := Len( aProdutos )
   ENDIF
   aProdutos[ nPos, 3 ] += Orcam->QTDE
   aProdutos[ nPos, 4 ] += Orcam->vl_total

   RETURN NIL
Aqui dá pra perceber regrinhas tradicionais interessantes:

- Um problemão dividido em probleminhas
- Cada "bloco" tratando do seu assunto
- Variáveis locais, cada rotina tem suas variáveis, acabou simplificando o uso de variáveis também
- Rotinas pequenas, de fácil manutenção, deixa visível o processo da rotina

Depois de anos sem ver o fonte, uma olhada rápida e já dá pra alterar.

Ou... um fonte pensando no programador, que é quem olha o fonte.
Sinceramente, ninguém nunca me falou isso desse jeito, antes eu pensava que tudo isso era só pro compilador trabalhar melhor, e não dava atenção.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
fladimir
Colaborador
Colaborador
Mensagens: 2445
Registrado em: 15 Nov 2006 20:21

Uma mudança de hoje: FOR EACH

Mensagem por fladimir »

vlw
Sun Tzu há mais de três mil anos cita nas epígrafes de seu livro “A Arte da Guerra“:

“Concentre-se nos pontos fortes, reconheça as fraquezas, agarre as oportunidades e proteja-se contra as ameaças”.
“Se não é vantajoso, nunca envie suas tropas; se não lhe rende ganhos, nunca utilize seus homens; se não é uma situação perigosa, nunca lute uma batalha precipitada”
.


Até 2017    Desktop Console [ Legado ] Harbour | MinGW | DBF | CDX | FastReport | MySQL


Novos Projetos:

   Desktop Visual           Windev Desktop
   Celular Android/iOS   Windev Mobile
   WEB                            Windev Web


Sejamos gratos a Deus.
xfurlan
Usuário Nível 1
Usuário Nível 1
Mensagens: 3
Registrado em: 13 Ago 2016 17:19
Localização: Osasco

Uma mudança de hoje: FOR EACH

Mensagem por xfurlan »

Muito bom mesmo, gostei.
Assim voce não programou só para otimizações, ma tambem para facilitar compreensão que por sua vez facilita alterações futuras.
Aquele abraço.
xfurlan
sambomb
Usuário Nível 3
Usuário Nível 3
Mensagens: 250
Registrado em: 24 Out 2008 17:02
Localização: Itaocara - RJ - Brasil

Uma mudança de hoje: FOR EACH

Mensagem por sambomb »

Poderia construir esses ajustes em torno de um Objeto.
Por exemplo, esses métodos de acumular por cidade, produto, poderia preencher os valores para todos a serem acumulados enquanto obtem os dados e um método do objeto retornar as informações.
Imagem

Rca Sistemas - Itaocara - RJ
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Uma mudança de hoje: FOR EACH

Mensagem por JoséQuintas »

A de hoje:
A primeira coisa foi pensar num FOR/EACH pra simplificar, pra pegar o arquivo de data mais recente.

Código: Selecionar todos

   LOCAL nCont, nNumFile, cDateTime, acFileList, mEmail

   acFileList := Directory( AppEmpresaApelido() + "-backup*.zip" )
   IF Len( acFileList ) == 0
      MsgStop( "Crie primeiro o arquivo na opção de backup!" )
      RETURN
   ENDIF
   nNumFile  := 0
   cDateTime := "000000000:00:00"
   FOR nCont = 1 TO Len( acFileList )
      IF Dtos( acFileList[ nCont, 3 ] ) + acFileList[ nCont, 4 ] > cDateTime
         nNumFile := nCont
         cDateTime := Dtos( acFileList[ nCont, 3 ] ) + acFileList[ nCont, 4 ]
      ENDIF
   NEXT
   SayScroll( "O arquivo que será transmitido é " + acFileList[nNumFile,1] )
   SayScroll( "Foi criado em " + Dtoc( acFileList[ nNumFile, 3 ] ) + " " + acFileList[ nNumFile, 4 ] )
   SayScroll( "Seu tamanho é de " + LTrim( Str( Int( acFileList[ nNumFile, 2 ] / 1024 ) ) ) + " kb " )
   SayScroll()
   IF Int( acFileList[ nNumFile, 2 ] / 1000 ) > 20000
      SayScroll( "ATENÇÃO!!! A central de emails pode recusar o tamanho acima de 2mb!",, .T. ) 
      SayScroll()
   ENDIF
   IF ! MsgYesNo( "Confirma o envio do backup de " + Dtoc( acFileList[ nNumFile, 3 ] ) + " para JPA?" )
     RETURN
   ENDIF
   IF ( Date() - acFileList[ nNumFile, 3 ] ) > 1
      IF ! MsgYesNo( "ATENÇÃO!!! Backup tem mais de um dia " + Dtoc( acFileList[ nNumFile, 3 ] ) + ". Continua?" )
         RETURN
      ENDIF
   ENDIF
Alterei a referência para o elemento do array ao invés da posição, e no final, o ASort simplificou mais do que FOR/EACH.
Até variáveis, reduziu de 5 pra 3.

Código: Selecionar todos

   LOCAL acFileList, mEmail, aFileToSend

   acFileList := Directory( AppEmpresaApelido() + "-backup*.zip" )
   IF Len( acFileList ) == 0
      MsgStop( "Crie primeiro o arquivo na opção de backup!" )
      RETURN
   ENDIF
   ASort( acFileList, , , { | a, b | Dtos( a[ F_DATE ] ) + a[ F_TIME ] > Dtos( b[ F_DATE ] ) + b[ F_TIME ] } )
   aFileToSend := acFileList[ 1 ]
   SayScroll( "O arquivo que será transmitido é " + aFileToSend[ F_NAME ] )
   SayScroll( "Foi criado em " + Dtoc( aFileToSend[ F_DATE] ) + " " + aFileToSend[ F_TIME ] )
   SayScroll( "Seu tamanho é de " + LTrim( Str( Int( aFileToSend[ F_SIZE ] / 1024 ) ) ) + " kb " )
   SayScroll()
   IF Int( aFileToSend[ F_SIZE ] / 1000 ) > 20000
      SayScroll( "ATENÇÃO!!! A central de emails pode recusar o tamanho acima de 2mb!",, .T. )
      SayScroll()
   ENDIF
   IF ! MsgYesNo( "Confirma o envio do backup de " + Dtoc( aFileToSend[ F_DATE ] ) + " para JPA?" )
     RETURN
   ENDIF
   IF ( Date() - aFileToSend[ F_DATE ] ) > 1
      IF ! MsgYesNo( "ATENÇÃO!!! Backup tem mais de um dia " + Dtoc( aFileToSend[ F_DATE ] ) + ". Continua?" )
         RETURN
      ENDIF
   ENDIF
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Responder