Ler dados de um arquivo com multiplos valores

Olá, pessoal! Eu sou novo aqui no fórum…

Tudo bem? Então, o meu professor passou o seguinte problema:

Considere que sua empresa seja contratada pela Superliga de Vôlei Nacional para resolver o problema da divulgação dos resultados das competições que ela mantém.

Sua empresa deve desenvolver um algoritmo que, dados um arquivo de entrada (LIDO SOMENTE UMA VEZ PELO SEU PROGRAMA), com todos os jogos de algum turno da Superliga, e o número de times que devem ser classificados para a próxima fase (N), retorne os N times da próxima fase em um arquivo de saída bem especificado. Sabe-se, analisando as regulamentações da CBV que, em caso de:

 VITÓRIA ou por 3x0, ou por 3x1 – o vencedor ganha três pontos;
 DERROTA ou por 0x3, ou por 1x3 – o perdedor não ganha nenhum ponto;
 VITÓRIA por 3x2 – o vencedor ganha dois pontos; e
 DERROTA por 2x3 – o perdedor ganha um ponto.

Se times estiverem empatados em pontuação, o critério de desempate é o número de vitórias. Se eles também estiverem empatados em número de vitórias, o critério de desempate será o saldo de pontos em sets, isto é, a diferença entre os todos os pontos feitos por uma quipe e todos os pontos que os outros times fizeram nela. O seu programa deve retornar, no arquivo de saída “out­” acrescido do nome de arquivo de entrada, os N times da próxima fase.

Por exemplo, dados os resultados de um turno deste ano (Liga 2015-2016), cujo o nome é result­fase2­2016.txt:

VOLEI NESTLE vs REXONA­-ADES/3­-2/25­-22/14­-25/26-­24/19­-25/15-­10
DENTIL­-PRAIA CLUBE vs CAMPONESA-MINAS/3­-2/22-­25/25­-15/21­-25/25-­22/15-­12
REXONA­ADES vs VOLEI NESTLE/3-­1/21-­25/25­-22/25­-23/25­-16
CAMPONESA-­MINAS vs DENTIL-­PRAIA CLUBE/3-­1/21-­25/25­-17 25-­22/ 25-­22
REXONA­ADES vs VOLEI NESTLE/3-­0/25­-20/25­-23/25-­16
DENTIL-­PRAIA CLUBE vs CAMPONESA-­MINAS/3­-0/25-­21/25­-18/25-­22

O resultado deverá ser:

REXONA­-ADES
DENTIL ­PRAIA CLUBE

Eu pensei em fazer o seguinte: eu leio a linha do arquivo, separo a parte das equipes e dos pontos e tento colocar isso dentro de uma matriz, por exemplo:

Time 1 vs Time 2 /3­-2/25­-22/14­-25/26-­24/19­-25/15-­10

Separo a parte das equipes: Time 1 e time 2 e coloco dentro da matriz fazendo mais ou menos a seguinte estrutura:

Equipe| Vitorias| Derrotas | Total de pontos
Time1 | | |
Time2 | | |
E assim sucessivamente…
Mas as minhas dúvidas são as seguintes, como que vou referenciar A string Time 1 a quantidade de vitórias/derrotas que ela teve durante as partidas?

Por exemplo: no primeiro caso, VOLEI NESTLE vs REXONA­-ADES/3­-2/25­-22/14­-25/26-­24/19­-25/15-­10 a equipe vencedora foi "Volei Nestle"e iremos dizer que ela seja o “time 1”, aí conto uma vitória para ela, mas no terceiro jogo, essa mesma equipe, perdeu… e aí eu penso, como voltar na matriz para contabilizar a derrota dessa equipe?

Aí vi que - talvez - usar matriz para esse problema não seja o ideial, portanto quais estruturas de dados me aconselham a estudar?

Eu queria algo que eu pudesse criar uma espécie de array associativo, assim como faz no php para que eu pudesse associar um indice a uma chave, criando mais ou menos o seguinte:

Time1=> array(NumVitorias,NumDerrotas,Total)
Time2=> array(NumVitorias,NumDerrotas,Total)
.
.
.
E o mesmo para os demais times. Vocês acham que isso é uma boa ideia? Qual seria uma estrutura no qual eu poderia implementar esse problema? Eu andei lendo sobre hashmap, mas não entendi muito bem…mas qual o conselho de vocês?

Desculpem se não fui muito objetivo, ou claro, qualquer coisa tento explicar novamente!

Desde já, agradeço!

Uma forma que eu uso MUITO para trabalhar com esses tipos de dados, é o formato json. Onde você pode salvar um array com os seguintes dados, “PontuacaoPlacar1”:[“2x3”,“2x4”,“3x4”,“4x4”,“5x4”,“6x4”]. Ai você pegar os valores em cada ponto do array e separa pelo x. Por exemplo:

var json={
  "PontuacaoPlacar1":["2x3","2x4","3x4","4x4","5x4","6x4"]
}
for(var i=0;i<json.PontuacaoPlacar1.length;i++){
 var placar=json.PontuacaoPlacar1[i];
 var time1=placar.substring(0,placar.indexOf('x'));
 var time2=placar.substring(placar.indexOf('x')+1);
 console.log(placar);//imprimi por exemplo 2x3
 console.log(time1);//imprimi por exemplo 2
 console.log(time2);//imprimi por exmplo 3
}

A vantagem desse formato, é que você pode transformar todo o objeto json, por mais grande que ele seja, em uma string normal. Enviar para onde você quiser (até para salvar no banco de dados), e depois simplesmente converter essa string para json novamente quando você for usar.

A estrutura seria HashMap

HashMap<String, int[]> map = new HashMap<>();

String time = "time1";
int[] resultados = new int[] {5, 6, 11};

// coloca no map
map.put(time, resultados);

// obtem do map
resultados = map.get(time);

Eu estou tentando com listas encadeada também, mas não sei se dará certo. Em breve posto os resultados e as dúvidas. O problema de trabalhar com o hashmap é que antes de jogar dentro do hashmap eu teria trabalhar nos resultados primeiro, separando as strings e e tals. Uma outra dúvida seria a seguinte:

ANtes de eu jogar os resultados para dentro do meu hashmap, eu tenho que ter todos os dados do número de derrotas, de vitórias e total de pontos, né?

Obtem a linha, separa a linha, atualiza o map

int[] result = map.get(time);
if (result == null) {
    result = new int[]{0,0,0};
    map.put(time, result);
}
// adiciona vitoria
result[0] = result[0] + 1;
// adiciona derrota
result[1] = result[1] + 1;
// adiciona total
result[2] = result[2] + 1;

e depois mude a linha

Se o map.get(time) retornar null, então ainda não existe resultado associado ao time ou não existe time no map.


Para obter todos os times e resultados do map

for (String time : map.keySet()) {
    int[] resultado = map.get(time);
    System.out.println(time);
    System.out.println(Arrays.toString(resultado));
}

Perfeito! Entendi a ideia, mas diego eu tenho outra dúvida, é possível ordenar o meu map de acordo com os dados do meu array? Ordenar pelos valores em vez de chave? Segue uma ideia:

Estrutura do meu map = ( Time, array [ vitoria, derrota, total ] )

Valores dentro do meu map:

Time1, [1,2,5]
Time2, [3,0,9]
Time3, [5,6,1]
Time4, [2,1,6]

Após ordenar, de acordo com quem possui o maior total

Time2, [3,0,9]
Time4, [2,1,6]
Time1, [1,2,5]
Time3, [5,6,1]

Fazer uma ordenação desse tipo com a estrutura map não é possível, né? Eu deveria criar uma lista para que pudesse ordenar os dados? Eu li sobre o treemap, o problema é que ele organiza em ordem alfabética e isso não seria o caso. Há alguma maneira de ordená-lo ou só criando outro map para jogar os valores já ordenados ? Obrigado pelas ideias!

Não é possível.

A forma mais simples seria usando stream e expressao lambda

map.entrySet().stream().sorted((a, b) ->
                // a.getKey retorna o time, a.getValue retorna o resultado, [2] é o total
                Integer.compare(a.getValue()[2], b.getValue()[2]) * (-1)
        ).forEach(e -> {
                // e.getKey retorna o time, e.getValue retorna o resultado
                String time = e.getKey();
                int[] resultado = e.getValue();
                System.out.println(time);
                System.out.println(Arrays.toString(resultado));
                // aki vc pode adicionar numa nova lista
        });

A melhor forma seria criando classe Time

public class Time {
    String nome;
    int vitorias;
    int derrotas;
    int total;
}

HashMap<String, Time> map;

map.entrySet().stream()
  .map(e -> e.getValue())
  .sorted((a,b) -> b.total - a.total)
  .forEach(time -> {
    System.out.print("[ Nome " + time.nome);
    System.out.print("\tVitorias " + time.vitorias);
    System.out.print("\tDerrotas " + time.derrotas);
    System.out.println("\tTotal " + time.total + " ]");
  });

ou

List<Time> listaDeTimesOrdenados = map.entrySet().stream()
  .map(e -> e.getValue()) // converte o Stream de Map.Entry para Time
  .sorted((a,b) -> b.total - a.total) // ordena
  .collect(Collectors.toList()); // transforma em lista

Se você conseguir criar uma lógica, onde você pega um objeto (Time1) e extrai o valor total dele(nesse caso o 5), então é só você criar uma lista com esse e os outros objetos seguindo a mesma lógica de acessar o maior valor e depois você só usa um algorítimo de ordenação(ShellSort por exemplo), extrai o valor total e usa ele para comparar com o valor total dos outros objetos para ordenar. No fim, o shellsort te retorna uma lista ordenada. Viu é possível sim.

Oi, pessoal! Desculpa a demora, mas eu consegui fazer tudo. Eu usei classes e objetos e lista encadeada. Porque na hora de organizar os resultados ficava complicado, pois eu teria que organizá-lo do menor para o maior e então gravar em um arquivo de texto. Criei 3 classes, times, classificação e um dicionário. aí “amarrava” os times na classificação e deu certo! Obrigado Rodrigo e Diego!