Problema de lógica!

9 respostas
P

Olá! meu problema é o seguinte

Tenho uma array Bem longa neste formato
public Object [][] Nomes =  {			
			{0, "Nome1", -1},
			{100, "Nome2" , 1205},
			{300, "Nome3", 1203},
			{500, "Nome4", 1207},
			{700, "Nome5", 1217},
			{900, "Nome6", 1209},
			{1100, "Nome7", 1211},
			{1200, "Nome8", 1211},
			{1300, "Nome9", 1213},
			{1400, "Nome10", 1213},
      }

Certo Então o primeiro é o Id, e o segundo é o nome, o terceiro podem ignorar.
Então eu preciso ver o nome da pessoa se baseando no id atual então eu fiz o seguinte:

Irei procurar o nome Com a id de 500 Então SearchingId = 500;
for (int i = 0; i < Nomes.length; i++) {
         int NomeAchado = Integer.valueOf(String.valueOf(Nomes[i][0]));
         if (SearchingId == NomeAchado) {
            System.out.println("Found Name Id: " + NomeAchado);
            System.out.println("Name: " + String.valueOf(Nomes[i][1]));
            return;
         }
      }
Assim perfeito funcionando corretamente ele ira retornar o "Nome4"; Só que quando ele não axa o id que está procurando, eu queria que ele retornasse o anterior mais próximo, então por exemplo
SearchingId = 800;
Ele teria que retornar o "Nome5" pois é o anterior mais próximo. Bem então foi isso que eu fiz, logo em baixo dessa parte de código que mostrei acima:
for(int i = 0; i <= 200; i++){
            for (int id = 0; id < Nomes.length; id++) {
               int NomeAchado = Integer.valueOf(String.valueOf(Nomes[id - ((id - i) > 0 ? i : 0)][0]));
               if ((NomeAchado + i) == SearchingId) {
                  System.out.println("Nearest User: " + String.valueOf(Nomes[id - ((id - i) > 0 ? i : 0)][1]));
                  return;
               }
               System.out.println("Searching: " + FoundUser + "/" + SearchingId + "/" + i);            
            Searching++;
         }
      }
Certo, isso até da meio certo só que veja bem: ele passa 200 veses pela array inteira, a array é bem grande axo que o length dela eh uns 200 ou mais, então as veses o número coencide com um usuário com uma id muito mais baixa, e desse jeito ele irá procurar sempre numa diferença de 200 ids entre cada 1, mas além de muito demorado axo pouco prático e não está funcionando muito bem. Talves para explicar melhor: Se eu não pudesse fazer isso que estou pedindo, para ele retornar o nome que está entre 700 - 899 Eu teria que ir adicionando
{700, "Nome5", 1217},
{701, "Nome5", 1217},
{702..., "Nome5", 1217},
Até
{799, "Nome5", 1217},

Então a minha pergunta é:

Alguém tem uma idéia melhor? =D

Obrigado, espero que tenha sido bem claro!

9 Respostas

M

Olá pb600,

Talvez isso ajude…

public static Object [][] Nomes =  {			
			{0, "Nome1", -1},
			{100, "Nome2" , 1205},
			{300, "Nome3", 1203},
			{500, "Nome4", 1207},
			{700, "Nome5", 1217},
			{900, "Nome6", 1209},
			{1100, "Nome7", 1211},
			{1200, "Nome8", 1211},
			{1300, "Nome9", 1213},
			{1400, "Nome10", 1213},
	};
	
	public static void main(String[] args) {

		int idx = getIndex(600);
		
		if (idx == -1) {
			System.out.println("Erro");
		}
		else {
			System.out.println((Nomes[idx][1]).toString());
		}
			
		
	}
	
	public static int getIndex(int searchingId ) {

		int oldIndex = 0;
		
		for (int i = 0; i < Nomes.length; i++) {
			
			int id = ((Integer)Nomes[i][0]).intValue();
			
			//Id encontrado
			if (id == searchingId) {
				return i;
			}
			
			//Salva o último id "menor"
			if (id < searchingId) {
				oldIndex = i;
			}
			
			//Caso o id procurado ultrapassou, retorna o último id "menor"
			if (id > searchingId) {
				return oldIndex;
			}
		}
		
		//Caso o valor a ser procurado esteja totalmente fora do esperado
		return -1;
		
	}

Veja que aqui você percorre todos os ids, e caso o próximo seja maior do que o procurado, retorna o anterior.
Mas esta lógica só funciona se os ids estiverem em ordem crescente.

Até mais.

GuilhermeKFreitas

Opa, e aí @pb600, beleza ?

Então, só pra saber, você precisa trabalhar somente com arrays, ou você pode utilizar a API do Java ??

Se você puder, aconselho a dar uma olhada na classe TreeMap.
http://download.oracle.com/javase/6/docs/api/java/util/TreeMap.html

Na minha opinião, a primeira coisa a fazer seria tentar abstrair melhor as propriedades ali. Eu criaria uma classe Pessoa simples, com os atributos id e nome.

public class Pessoa {
	private int id;
	private String nome;
	
	public Pessoa(int id, String nome){
		this.id = id;
		this.nome = nome;
	}
		
        // getters e setters omitidos
	
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return id + ": "+ nome;
	}
}

A partir daí, em vez de percorrer os arrays, eu usaria a classe TreeMap para isso !
Ela tem algumas características como:

  • é considerado um mapa: possue chaves/valores;
  • não permite chaves duplicadas;
  • mantém a ordem natural das suas chaves (ou pode ser fornecido um Comparator);
  • possui um método justamente para o que você quer !

Então ficaria mais ou menos assim:

public static void main(String[] args) {

            /* Instancio uma TreeMap que tem como chave um Integer (no nosso caso, é o id da Pessoa), e como valor o próprio objeto pessoa!
                */
		TreeMap<Integer,Pessoa> mapaDePessoas = new TreeMap<Integer,Pessoa>();
		
                Pessoa p1 = new Pessoa(300, "Guilherme" );
		Pessoa p2 = new Pessoa(400, "João");
		Pessoa p3 = new Pessoa(500, "Juliana");
		
                // aqui inserimos no mapa cada objeto
		mapaDePessoas.put(p1.getId(), p1);
		mapaDePessoas.put(p2.getId(), p2);
		mapaDePessoas.put(p3.getId(), p3);
		
                // utilizamos o método floorKey(). Ele recebe um objeto, e procura pra ver se encontra a maior chave igual ou menor que ela no mapa.
                // Nesse exemplo, estamos procurando pela chave 490 !
		Integer chave = mapaDePessoas.floorKey(490);                // Como não tem essa chave, ele retorna a anterior a esta ! No caso, retorna o id 400 !
		
                // depois, utilizamos esse mesma chave para retornar o valor associado à ela (no caso, o objeto Pessoa).
		Pessoa pessoa = mapaDePessoas.get(chave);

                // exibimos a pessoa.
		System.out.println(pessoa);
		
	}

Não sei se está é a melhor implementação… mas acho que está melhor do que ficar trabalhando com arrays.
Dessa forma você deixa todo o trabalho sujo para a classe da API.
Mas enfim, a galera pode ter outra idéias melhores que essa.

Falows…

hudsonpereira

Realmente muito útil esse método, mas se o carinha está estudando lógica, ele mesmo é que tem que projetar os algoritmos…

Mas se fosse para desenvolver uma aplicação, sim, seria reinventar a roda.

GuilhermeKFreitas
Nota:

O link da documentação que você postou não consta o método que você utilizou…

Se alguém quiser visitar procure na documentação do Java 6

ou siga o link:
http://download.oracle.com/javase/6/docs/api/java/util/TreeMap.html

A classe realmente acaba com o seu problema.

GuilhermeKFreitas

É verdade, o problema é mais de lógica mesmo né !
Bom, de qualquer forma, é uma opção pra quem quer uma forma mais “robusta”, hehe…

Aah, valeu. Nem tinha percebido o link errado.
Eu editei meu post lá !

C

Cara fiz esse código meio rápiso, acho que te atende, a primeira coisa que faço é criar uma tabela com o indice do array, com isso vc só precisará iterar seu array apenas uma vez se o código existir, e se o código não existir, o método getNomeProximo busca pelo próximo nome imediatamente anterior ao id informado.

espero ter ajudado.

import java.util.Map;
import java.util.TreeMap;

public class TestesComArray {

	public Object [][] nomes =  {             
			{0, "Nome1", -1},  
			{100, "Nome2" , 1205},  
			{300, "Nome3", 1203},  
			{500, "Nome4", 1207},  
			{700, "Nome5", 1217},  
			{900, "Nome6", 1209},  
			{1100, "Nome7", 1211},  
			{1200, "Nome8", 1211},  
			{1300, "Nome9", 1213},  
			{1400, "Nome10", 1213},
			};
	
	
	Map<Integer, Integer> posicoes = null;   
	
	private void montarPosicoes(){
		posicoes = new TreeMap<Integer, Integer>();
		for(int i=0;i<nomes.length;i++){
			posicoes.put((Integer)nomes[i][0], i);
		}
	}
	
	
	public void getNome(Integer id){
		if(posicoes == null)
			montarPosicoes();
		Object[] dadosDoUsuario = null;
		
		if(posicoes.containsKey(id)){
			dadosDoUsuario = nomes[posicoes.get(id)];
		}else{
			dadosDoUsuario = nomes[getNomeProximo(id)];
		}
		System.out.println(dadosDoUsuario[0]+"-"+dadosDoUsuario[1]);
		
	}

	public Integer getNomeProximo(Integer id){
		id = --id;
		if(posicoes.containsKey(id))
			return posicoes.get(id);
		
		return getNomeProximo(id);
	}
	
	
	public static void main(String[] args) {
		TestesComArray t = new TestesComArray();
		t.getNome(1301);
	}

}
C

O método getNomeProximo pode ser melhorado aumentando ainda mais a performance.

public Integer getNomeProximo(Integer id){
		if(id >= nomes.length)
			return nomes.length-1;
		
		id = --id;
		if(posicoes.containsKey(id))
			return posicoes.get(id);
		
		return getNomeProximo(id);
	}
P

Haha nossa! muito obrigado pelas respostas, eu vou analizar um por um, eu não estou estudando lógica.
Ei mrsuzuki , sim eu ja havia resolvido este problema fazendo o que você falou, só que ai fica pouco flexível =D

R

sei la... parece q ele nao quer usar Map não... só array mesmo

eu usaria seu método mas faria assim...

int NomeMaior = 0;
int NomeMenor = 0;
int result;

for (int i = 0; i < Nomes.length; i++) {  

   int NomeAchado = Integer.valueOf(String.valueOf(Nomes[i][0]));  
   
   if (SearchingId == NomeAchado) {  

      System.out.println("Found Name Id: " + NomeAchado);  
      System.out.println("Name: " + String.valueOf(Nomes[i][1]));  

      return;  
   }

   // se chegar aqui, passou do numero procurado
   if ( SearchingId > NomeAchado ) {

      NomeMaior = Integer.valueOf(String.valueOf(Nomes[i][0])); 

      if ( (NomeMaior - NomeAchado) < ( NomeAchado - NomeMenor) ) {

           result = NomeMaior;        
      }else{

           result = NomeMenor;
      }

      System.out.println("Found Name Id: " + NomeAchado);  
      System.out.println("Name: " + String.valueOf(Nomes[i][1]));  
   }

   // se chegou aqui, não encontrou o nome e nem o mais proximo ainda então atribuo o i ao NomeMenor
   NomeMenor =Integer.valueOf(String.valueOf(Nomes[i][0])); 
}

fiz na unha aqui no forum veja se tem algo errado ae e da uma corrigida... a ideia eh essa =)

P

Tem razão prefiro array =D obrigado =D

Criado 19 de janeiro de 2011
Ultima resposta 21 de jan. de 2011
Respostas 9
Participantes 6