Página 1 de 3
vetor: busca maior número
Enviado: 17 Jun 2021 01:24
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?
vetor: busca maior número
Enviado: 17 Jun 2021 15:08
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.
vetor: busca maior número
Enviado: 17 Jun 2021 16:50
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.
vetor: busca maior número
Enviado: 17 Jun 2021 21:18
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.
vetor: busca maior número
Enviado: 17 Jun 2021 21:29
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
//------------------------------------------------------------------------------------------
vetor: busca maior número
Enviado: 17 Jun 2021 21:32
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.
vetor: busca maior número
Enviado: 17 Jun 2021 21:51
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.
vetor: busca maior número
Enviado: 17 Jun 2021 22:03
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.
vetor: busca maior número
Enviado: 18 Jun 2021 00:36
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?
vetor: busca maior número
Enviado: 18 Jun 2021 10:06
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?
vetor: busca maior número
Enviado: 18 Jun 2021 10:11
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.
vetor: busca maior número
Enviado: 18 Jun 2021 10:18
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
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.
vetor: busca maior número
Enviado: 18 Jun 2021 11:35
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.
vetor: busca maior número
Enviado: 18 Jun 2021 12:19
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.
Nota: Só vale pra JUNHO, porque nem me preocupei em servir pra outros meses, por achar que isso vai ser diferente.
vetor: busca maior número
Enviado: 18 Jun 2021 13:28
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.