vetor: busca maior número

Projeto [x]Harbour - Compilador de código aberto compatível com o Clipper.

Moderador: Moderadores

cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

vetor: busca maior número

Mensagem por cjp »

Pessoal, estou precisando de uma ajuda.
Preciso encontrar um número entre 9 variáveis, que atenda às seguintes especificações: o número precisa ser o maior nvenc possível, desde que o nmelh seja igual ou maior que o dia atual.

Criei um vetor assim:

Código: Selecionar todos

		 aadd(nvestr,{crt1,nvenc1,nmelh1})
		 aadd(nvestr,{crt2,nvenc2,nmelh2})
		 aadd(nvestr,{crt3,nvenc3,nmelh3})
		 aadd(nvestr,{crt4,nvenc4,nmelh4})
		 aadd(nvestr,{crt5,nvenc5,nmelh5})
		 aadd(nvestr,{crt6,nvenc6,nmelh6})
		 aadd(nvestr,{crt7,nvenc7,nmelh7})
		 aadd(nvestr,{crt8,nvenc8,nmelh8})
		 aadd(nvestr,{crt9,nvenc9,nmelh9})
Como faço para pegar o registro que atenda aos requisitos antes enunciados?

Alguém pode me ajudar?
Inacio de Carvalho Neto
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

vetor: busca maior número

Mensagem por alxsts »

Olá!
cjp escreveu:Alguém pode me ajudar?
Poste este array contendo alguns valores para que tenhamos uma ideia dos tipos de dados que ele contem.
[]´s
Alexandre Santos (AlxSts)
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

vetor: busca maior número

Mensagem por cjp »

A array contém apenas o nome (campo com até 15 caracteres) e dias (os campos nvenc e nmelh são campos numéricos com até dois dígitos).

Exemplo:

XXXXXXXXX, 01, 22
yyyyyyyyyy, 05, 25
ZZZZZZZZZ, 08, 31
etc.
Inacio de Carvalho Neto
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

vetor: busca maior número

Mensagem por JoséQuintas »

cjp escreveu:Preciso encontrar um número entre 9 variáveis, que atenda às seguintes especificações: o número precisa ser o maior nvenc possível, desde que o nmelh seja igual ou maior que o dia atual.
Tô achando a pesquisa esquisita, mas....

O maior vencimento, com número igual ou maior.
Se pensar no MySQL e ORDER BY....

Primeiro é ordenar esse array por vencimento decrescente, e dia decrescente.
Depois é pegar o primeiro que encontrar, com número maior ou igual ao dia atual, sem nem precisar comparar data pra saber qual é maior.

Em MySQL seria
SELECT * FROM tabela WHERE NUMERO >= diaatual ORDER BY DATA,DIA DESC

Em array, o ASort() pra colocar em ordem, e o ASCan() pra pesquisar.

Legal né.... acaba sendo a mesma lógica.

Exatamente o que comentei em outro post: é tudo tabela, apenas nunca pensamos nisso, mas o SQL pensou.
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/
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

vetor: busca maior número

Mensagem por alxsts »

Olá!

Teste isto:

Código: Selecionar todos

#include "inkey.ch"

FUNCTION Main()

   LOCAL nDay, GetList := {}

   SetMode( 25,80 ) ; CLS

   nDay := Day( Date() )

   While Lastkey() != K_ESC
      @ 10,10 Say "Informe o dia    :" ;
              Color "W+/B" ;
              Get nDay ;
              Color "W+/B, B+/W" ;
              Pict "99" ;
              VALID nDay > 0 .And. nDay < 32
      READ

      @ 12,10 Say "Valor encontrado : " + Transform( BuscaVal( nDay ), "@99" ) Color "W+/B"

      @ 16,10 Say "Tecle algo..." Color "W+/B" 

      Inkey(0)

      @ 12,10 CLEAR TO 16,70
   Enddo

RETURN NIL
//------------------------------------------------------------------------------------------

// Posições em aArray
#define A_DESCRIÇAO    1
#define A_VENCIMENTO   2
#define A_MELHOR_DIA   3

FUNCTION BuscaVal( nDay )

   LOCAL aArray, e, nMax

   aArray := { { "Lorem ipsum sod",  1,  2 }, ;
               { "ales senectus ",   5,  4 }, ;
               { "donec sociosqu ", 10,  6 }, ;
               { "scelerisque ",    15,  8 }, ;
               { "pharetra primis", 20, 10 }, ;
               { "blandit odio ",   25, 12 }, ;
               { "dui massa ",      30, 14 }, ;
               { "vivamus ",         2, 16 }, ;
               { "himenaeos ",       7, 18 }, ;
               { "euismod ac ",     12, 20 }, ;
               { "semper ",         19, 22 }, ;
               { "facilisis vitae", 26, 24 }, ;
               { "sagittis ",       31, 15 }, ;
               { "faucibus ",        3, 28 }, ;
               { "viverra ",         8, 30 }, ;
               { "vestibulum nisi", 13,  1 }, ;
               { "sodales congue",  18,  3 }, ;
               { "dolor quisque",   23,  5 }, ;
               { "amet",            28,  7 }, ;
               { "gravida augue",    4,  9 }, ;
               { "luctus ut vel",    9, 11 }, ;
               { "tellus potenti",  14, 13 } ;
             }

   nMax := 0

   // Para cada elemento e no aArray...
   For Each e In aArray
      // Cada elemento também é um array...
      // Se a terceira posição do elemento for maior ou igual ao dia em nDay...
      If e[ A_MELHOR_DIA ] >= nDay
         // Se a segunda posição do elemento for maior que o anterior,
         // guarda o valor da segunda posição do elemento
         nMax := If( e[ A_VENCIMENTO ] > nMax, e[ A_VENCIMENTO ], nMax )
      Endif
   Next

RETURN nMax
//------------------------------------------------------------------------------------------
[]´s
Alexandre Santos (AlxSts)
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

vetor: busca maior número

Mensagem por cjp »

Não estou usando MySQL neste caso. Os dados estão diretamente no prg mesmo.
O problema é que eu não sei lidar bem com vetores. Nem sei se a melhor forma de fazer isso é mesmo com vetor.
Se for necessário, posso criar uma tabela no MySQL para extrair os dados da forma como vc disse. Mas, se for possível evitar isso, seria melhor.
Inacio de Carvalho Neto
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

vetor: busca maior número

Mensagem por JoséQuintas »

É que como não faz parte do dia a dia, também tenho que pesquisar.
Talvez ajude pensar como falei, o array é uma tabela com campos, ao invés de nomes são números.
Me confundo se é > ou <
E também se no ASCan() é mesmo assim, ou se só no hb_AScan() aceita codeblock no primeiro parâmetro.

Código: Selecionar todos

#define ITEM_DATA 2
#define ITEM_DIA   3

FUNCTION MelhorDia( nDiaAtual )

LOCAL aList := { .... }
LOCAL nPos

ASort( aList, { | a, b | a[ ITEM_DATA ] > b[ ITEM_DATA ] .OR. ( a[ ITEM_DATA ] == b[ ITEM_DATA ] .AND. a[ ITEM_DIA ] > b[ ITEM_DIA ] ) } )

nPos := AScan( aList, { | e | e[ ITEM_DIA ] >= nDiaAtual } )

RETURN aList[ nPos, ITEM_DATA ]
Nota: Editado pra corrigir o resultado pra data, e não posição numérica.
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

vetor: busca maior número

Mensagem por JoséQuintas »

Só pra avisar que editei o post anterior, e também pra explicar:

Colocando em ordem de data decrescente e dia decrescente, já vai estar na ordem correta de maior data e maior número.
Desse jeito vai ser o primeiro que encontrar.

o ASort() usa as colunas data e dia pra isso, colunas 2 e 3 (ITEM_DATA e ITEM_DIA)
o ASCan() pesquisa o dia, portanto coluna 3 (ITEM_DIA)
No caso de array, o #define ajuda a usar uma espécie de nome, ao invés de usar o número, o que facilita "não errar".
Como o retorno do ASCan() é a posição (por isso chamei a variável de nPos), é pegar a informação dessa posição.

O array é como o DBF, tem seus registros (1,2,3,...), e cada registro tem seus campos (1,2,3)
o ASort() acaba sendo uma espécie de indexação, mas direta, sem índice.
e o ASCan() acaba sendo uma espécie de SEEK, que retorna o número do registro.
No final é o registro nPos, e o campo 3 (a Data). aList[ nPos, 3 ] ou no fonte com #define, aList[ nPos, ITEM_DATA ]
Talvez pensando desse jeito ajude a entender melhor o array.
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/
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

vetor: busca maior número

Mensagem por cjp »

Adaptei aqui e funcionou, mas acho que não corretamente.
Fiz assim:

Código: Selecionar todos

function crtmelh
         local crtm, crt2m, crt3m, crt4m
		 local aList :={}
         LOCAL nPos
         local crt1 :="I...."
		 local nvenc1 :=1
		 local nmelh1 :=23
		 local crt2 :="O...."
		 local nvenc2 :=5
		 local nmelh2 :=28
		 local crt3 :="B...."
		 local nvenc3 :=8
		 local nmelh3 :=24
		 local crt4 :="V..."
		 local nvenc4 :=12
		 local nmelh4 :=2
		 local crt5 :="N..."
		 local nvenc5 :=18
		 local nmelh5 :=11
		 local crt6 :="C..."
		 local nvenc6 :=20
		 local nmelh6 :=10
		 local crt7 :="S..."
		 local nvenc7 :=22
		 local nmelh7 :=10
		 local crt8 :="R..."
		 local nvenc8 :=25
		 local nmelh8 :=11
		 local crt9 :="I..."
		 local nvenc9 :=28
		 local nmelh9 :=18
		 
		 aadd(aList,{crt1,nvenc1,nmelh1})
		 aadd(aList,{crt2,nvenc2,nmelh2})
		 aadd(aList,{crt3,nvenc3,nmelh3})
		 aadd(aList,{crt4,nvenc4,nmelh4})
		 aadd(aList,{crt5,nvenc5,nmelh5})
		 aadd(aList,{crt6,nvenc6,nmelh6})
		 aadd(aList,{crt7,nvenc7,nmelh7})
		 aadd(aList,{crt8,nvenc8,nmelh8})
		 aadd(aList,{crt9,nvenc9,nmelh9})

#define ITEM_DATA 2
#define ITEM_DIA   3

ASort( aList, { | a, b | a[ ITEM_DATA ] > b[ ITEM_DATA ] .OR. ( a[ ITEM_DATA ] == b[ ITEM_DATA ] .AND. a[ ITEM_DIA ] > b[ ITEM_DIA ] ) } )

nPos := AScan( aList, { | e | e[ ITEM_DIA ] >= day(date()) } )

?aList[ nPos, ITEM_DATA ]

inkey(11)
inkey(11)
Não sei se entendi o teu código, já que não entendo muito nem de vetor nem de codeblock.

Por que acho que não deu certo? Porque retornou a posição 1, tanto ontem (dia 17), quanto hoje (dia 18). Sendo que, na minha lógica, deveria retornar a posição 8 ontem e a posição 9 hoje.

Vou precisar pegar não apenas o primeiro, mas os 4 primeiros.

Outra dúvida: como faço para pegar o elemento crt?
Inacio de Carvalho Neto
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

vetor: busca maior número

Mensagem por JoséQuintas »

Código: Selecionar todos

#define ITEM_NOME 1
#define ITEM_DATA 2
#define ITEM_DIA  3

PROCEDURE Main

   LOCAL aItem

   SetMode(40,100)
   CLS
   Altd()
   aItem := CrtMelhor( Date() )
   ? aItem[ ITEM_NOME ]
   ? aItem[ ITEM_DATA ]
   ? aItem[ ITEM_DIA ]
   Inkey(11)

   RETURN

FUNCTION CrtMelhor( dData )

   LOCAL nPos, aList := { ;
      { "I....", 1, 23 }, ;
      { "O....", 5, 28 }, ;
      { "B....", 8, 24 }, ;
      { "V...", 12, 2 }, ;
      { "N...", 18, 11 }, ;
      { "C...", 20, 10 }, ;
      { "S...", 22, 10 }, ;
      { "R...", 25, 11 }, ;
      { "I...", 28, 18 } }

   ASort( aList,,,{ | a, b | a[ ITEM_DATA ] > b[ ITEM_DATA ] .OR. ( a[ ITEM_DATA ] == b[ ITEM_DATA ] .AND. a[ ITEM_DIA ] > b[ ITEM_DIA ] ) } )

   nPos := AScan( aList, { | e | e[ ITEM_DIA ] >= Day( dData ) } )

   RETURN aList[ nPos ]
Ok, tinha errado sobre como colocar o parâmetro no Asort()

Na lista, tem melhor 10, com dias 20 e 22, o dia 20 nunca vai ser usado.
Na lista, tem melhor 11, com dias 18 e 25, o dia 18 nunca vai ser usado.
Tem certeza sobre a escolha? faltou mencionar alguma coisa?
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

vetor: busca maior número

Mensagem por JoséQuintas »

O que achei estranho na forma que decidiu usar:

dias 1 a 18, retorna 28
dias 19 a 24, retorna 8
dias 25 a 28, retorna 5
acima disso, não retorna nada.

Faltou mencionar alguma coisa sobre seu critério.
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

vetor: busca maior número

Mensagem por JoséQuintas »

Teste prático:

Código: Selecionar todos

PROCEDURE Main

   LOCAL aItem, nDia

   SetMode(40,100)
   CLS
   Altd()
   FOR nDia = 1 TO 30
      aItem := CrtMelhor( Stod( "202106" + StrZero( nDia, 2 ) ) )
      ? nDia, aItem[ ITEM_NOME ], aItem[ ITEM_DATA ], aItem[ ITEM_DIA ]
   NEXT
   Inkey(11)

   RETURN
result.png
Então, de acordo com o que disse no primeiro tópico, seria isso.
Desse jeito, mais prático um IF/ELSE com 3 IFs.
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

vetor: busca maior número

Mensagem por JoséQuintas »

Outra coisa:
Não tem vencimento ANTES da emissão, então, trabalhar apenas com o dia não vai dar certo.
Mas ok, se o vencimento for menor que a emissão, seria mudar para o mês seguinte.

Acho que esse é mais um daqueles casos pra colocar no papel primeiro, pra ver se o que está pedindo é realmente o que está querendo como resultado.
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

vetor: busca maior número

Mensagem por JoséQuintas »

Só pra constar, o fonte atualizado que usei no último teste.

Código: Selecionar todos

##define ITEM_NOME 1
#define ITEM_DATA 2
#define ITEM_DIA  3

PROCEDURE Main

   LOCAL aItem, nDia

   SET DATE BRITISH
   SetMode(40,100)
   CLS
   Altd()
   FOR nDia = 1 TO 30
      aItem := CrtMelhor( Stod( "202106" + StrZero( nDia, 2 ) ) )
      ? nDia, aItem[ ITEM_NOME ], aItem[ ITEM_DATA ], aItem[ ITEM_DIA ], Stod( "2021" + iif( aItem[ ITEM_DATA ] >= nDia, "06", "07" ) + StrZero( aItem[ ITEM_DIA ], 2 ) )
   NEXT
   Inkey(11)

   RETURN

FUNCTION CrtMelhor( dData )

   LOCAL nPos, aList := { ;
      { "I....", 1, 23 }, ;
      { "O....", 5, 28 }, ;
      { "B....", 8, 24 }, ;
      { "V...", 12, 2 }, ;
      { "N...", 18, 11 }, ;
      { "C...", 20, 10 }, ;
      { "S...", 22, 10 }, ;
      { "R...", 25, 11 }, ;
      { "I...", 28, 18 } }

   ASort( aList,,,{ | a, b | a[ ITEM_DATA ] > b[ ITEM_DATA ] .OR. ( a[ ITEM_DATA ] == b[ ITEM_DATA ] .AND. a[ ITEM_DIA ] > b[ ITEM_DIA ] ) } )

   nPos := AScan( aList, { | e | e[ ITEM_DIA ] >= Day( dData ) } )
   IF nPos == 0
      RETURN { "nada", 0, 0 }
   ENDIF

   RETURN aList[ nPos ]
Alterei a função pra retornar a linha inteira, assim tem o nome também, e alterei pra retornar "nada" quando não encontra.
result.png
Nota: Só vale pra JUNHO, porque nem me preocupei em servir pra outros meses, por achar que isso vai ser diferente.
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/
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

vetor: busca maior número

Mensagem por cjp »

Ainda vou analisar e testar teus últimos posts, e também o do alxsts acima, mas vou adiantar uma informação: não vai ficar nenhum dia sem não.

Vou tentar ser mais claro: cada crt (crt1, crt2, etc) é um cartão, que tem uma data de vencimento (nvenc) e uma data de melhor dia de compra (nmelh).

Então, preciso pegar em cada dia qual cartão tem a data de vencimento mais distante (maior nvenc), desde que esteja no seu melhor dia de compra ou posterior.

Seria simples se todos os cartões tivessem igual distância entre a data de vencimento e a data de melhor compra. Ex: se fosse sempre de 10 dias a diferença, então o cartão que vence dia 25 teria melhor data em 15, o que vence dia 30 teria melhor data em 20, e assim por diante. Assim seria simples de fazer.

Mas infelizmente na prática não é assim. São bem variadas. E pode acontecer (e de fato acontece) de um cartão com vencimento posterior ter melhor data de compra antes de outro que tem vencimento anterior (ex: o de vencimento dia 25 tem melhor data de compra dia 10; o de vencimento dia 22 tem melhor data de compra dia 17). Neste caso o segundo cartão (com vencimento dia 22) será sempre segunda opção, jamais primeira. É isso que complica a questão, e é pra isso que estou me batendo com vetor (que não entendo bem).

Fiz-me entender?

Não vai ficar nenhum dia sem porque no dia 30, por exemplo, usaremos o crt2, cuja melhor data é o dia 28.

No papel, isso está certo. E eu até continuaria com isso só no papel. O problema é que essas datas/cartões sempre variam. Daí toda hora eu tenho que ficar refazendo, e isso dá um trabalho razoável. Por isso tive a ideia de fazer isso automaticamente. Para isso eu preciso quebrar a cabeça com esse vetor, para automatizar esse cálculo. Cada vez que mudar, eu só altero as datas e ele já calcula tudo automaticamente.
Inacio de Carvalho Neto
Responder