Simplifying the code
Let’s take a look at your code.
See this import:
import java.awt.List;
That is not the list you want to import. You are not using this List
for nothing, but what you really wanted to matter is the java.util.List
.
These variables:
private ArrayList<String>aParsear = new ArrayList<String>();
private HashMap<Integer,String> map = new HashMap<Integer,String>();
You can use the diamond syntax to avoid having to repeat the generics. Also, it is good practice to code for an interface and not an implementation. That is, to use List
and Map
(package java.util
) as types instead of ArrayList
and HashMap
. That is what would be the result:
private List<String> aParsear = new ArrayList<>();
private Map<Integer, String> map = new HashMap<>();
Let’s see how you transform the array into String
:
String tmp = ""+ resultado[0] + ", "
+ resultado[1] + ", "
+ resultado[2] + ", "
+ resultado[3] + ", "
+ resultado[4] + ", "
+ resultado[5] + "";
This would be much simpler and much better if it were so, besides not depending on the size of the array being fixed at 6:
StringJoiner sj = new StringJoiner(", ");
IntStream.of(resultado).boxed().map(Object::toString).forEach(sj::add);
String tmp = sj.toString();
Or, if you don’t have problems changing the format of the String
resultant:
String tmp = Arrays.toString(resultado);
Let’s see your if
:
if (...)
// Um monte de linhas aqui.
else
// Mais um monte de linhas aqui.
Please use the keys in this case because it is very easy for you to do nonsense when not putting them. For example:
if (algumaCoisa)
System.out.println("Estou dentro do if.");
System.out.println("Será que ainda estou dentro do if?");
By the way, further down, your code has this exact problem:
if(map.containsKey(chave))
System.out.println("ger,"+tmp);
map.put(chave,tmp);
}
I lost some time to understand the program because of that block up there. Identation suggests that the }
refers to the if
, but he’s actually from while
that’s on the outside. The fact that the code is incorrectly idented and does not use all the key pairs that should end up inducing whoever is reading the code to error.
See your bow tie while
:
Iterator<String> it = aParsear.iterator();
while(it.hasNext()){
String tmp = it.next();
Don’t use the Iterator
directly if you do not have a good reason to do so. Prefer the Enhanced-for:
for (String tmp : aParsear) {
Your list aParsear
actually consists of an array that you transform into String
to then transform back into array. That’s a gambiarra. To solve this, you can swap this code:
aParsear.add(tmp);
That’s why:
aParsear.add(resultado.clone());
And with that, you can eliminate the variable tmp
of the method busca
if you want.
That from here:
private ArrayList<String>aParsear = new ArrayList<String>()
Stay like this:
private List<int[]> aParsear = new ArrayList<>();
You can then simplify a lot of things on parsearListaGerada
thereby:
for (int[] valoresInteiros : aParsear) {
String tmp = Arrays.toString(valoresInteiros);
You can replace that:
System.out.println("Total de combinacoes: " + comb.count);
That’s why:
System.out.println("Total de combinacoes: " + comb.aParsear.size());
And then it can be erased:
// faz alguma coisa com um dos resultados possiveis
count++;
And that too:
private int count = 0;
private String[] temp;
We can simplify your if
with both for
s:
if ( (profundidade + 1) >= quantidade)
for(int x = inicio; x <= fim; x++){
resultado[profundidade] = numeros[x];
// Algumas coisas.
}
else
for(int x = inicio; x <= fim; x++){
resultado[profundidade] = numeros[x];
// Outras coisas.
}
And leave it so:
for (int x = inicio; x <= fim; x++) {
resultado[profundidade] = numeros[x];
if (profundidade + 1 >= quantidade) {
// Algumas coisas.
} else {
// Outras coisas.
}
}
Note that your Map
is used only within the method parsearListaGerada
and that after the use of the method, Map
does not contain any information that is relevant to be preserved. Therefore, put the Map
as a local variable of this method.
We can trade quantidade
for resultado.length
, and thereby eliminate this variable.
Prefer to use (String[] args)
instead of (String args[])
. So you preserve the declaration pattern [type of variable before and name of variable after] used in almost every other place in the Java language. Otherwise there is something in the format [a part of the type of the variable before, name of the variable in the middle, rest of the type of the variable after], which is somewhat confusing. The same goes for transforming int resultado[]
in int[] resultado
.
Assuming the list of numbers is always 1, 2, 3, 4... then you can delete the array numeros
and change the numeros[x]
for x + 1
.
A better name for your variable aParsear
would be volantes
.
To avoid your program getting fixed in 10 elements in the game with 6 on the wheel and you have to call comb.buscar(0, (10-6), 0);
in the main
, passing these magic numbers, you can introduce a constructor and a new method busca
:
private int[] resultado;
private List<int[]> volantes = new ArrayList<>();
public Combinacoes(int quantidade) {
this.resultado = new int[quantidade];
}
public void busca(int numeros) {
busca(0, numeros - resultado.length, 0);
}
And then in your main
you do that:
Combinacoes comb = new Combinacoes(6);
comb.busca(10);
There are still some other possible changes, but I think it is already good size here. The resulting code has exactly the same behavior as its original question code (except that it shows pairs of brackets for every sixfold in the output). Look at your code:
Simplified code
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Combinacoes {
private int[] resultado;
private List<int[]> volantes = new ArrayList<>();
public Combinacoes(int quantidade) {
this.resultado = new int[quantidade];
}
public void busca(int numeros) {
busca(0, numeros - resultado.length, 0);
}
private void busca(int inicio, int fim, int profundidade) {
for (int x = inicio; x <= fim; x++) {
resultado[profundidade] = x + 1;
if (profundidade + 1 >= resultado.length) {
System.out.println(Arrays.toString(resultado));
volantes.add(resultado.clone());
} else {
busca(x + 1, fim + 1, profundidade + 1);
}
}
}
private void parsearListaGerada() {
Map<Integer, String> map = new HashMap<>();
for (int[] valoresInteiros : volantes) {
String tmp = Arrays.toString(valoresInteiros);
int chave = 0;
for (int j = 0; j < valoresInteiros.length; j++) {
chave += ((j + 1) * valoresInteiros[j]);
}
if (map.containsKey(chave)) {
System.out.println("ger," + tmp);
}
map.put(chave, tmp);
}
System.out.println("Tamanho final:" + map.size());
System.out.println("Resultado final");
for (String valor : map.values()) {
System.out.println(valor);
}
}
public static void main(String[] args) {
Combinacoes comb = new Combinacoes(6);
comb.busca(10);
System.out.println("Total de combinacoes: " + comb.aParsear.size());
comb.parsearListaGerada();
}
}
Improving the code
I don’t understand what your idea with the chave
and with the Map
, but there are some elements in which the keys collide. For example:
[1, 2, 3, 4, 8, 9] - chave = 124
[1, 2, 3, 5, 6, 10] - chave = 124
[1, 2, 3, 4, 5, 9] - chave = 109
[1, 2, 4, 5, 6, 7] - chave = 109
[1, 2, 3, 5, 7, 9] - chave = 123
[1, 3, 4, 5, 6, 9] - chave = 123
This code will ultimately show where these key collisions occur, showing the 71 places that have them (this is the final size).
Considering that the result you aim at in the table that is in your question, don’t think this method procedure parsearListaGerada
makes sense to you. If I understand your question correctly, what you want is to eliminate results that have 5 or more repeated numbers. This method however just shows which are the steering wheels that have colliding keys. I ended up throwing out this method.
To redo everything, first let’s introduce a class Volante
:
private static final class Volante {
private final Set<Integer> numeros;
public Volante(int[] valores) {
this.numeros = IntStream.of(valores).boxed().collect(Collectors.toCollection(TreeSet::new));
}
public int dissimilaridade(Volante outro) {
List<Integer> interseccao = new ArrayList<>(numeros);
interseccao.removeAll(outro.numeros);
return interseccao.size();
}
@Override
public String toString() {
return numeros.toString();
}
}
The class name is self-explanatory. Its constructor converts a int[]
in a Set<Integer>
. The big draw is the method dissimilaridade(Volante)
which measures how many numbers differ between a steering wheel and another.
With this, we can make the following method:
private static List<Volante> limitarSimilaridade(List<Volante> volantes, int dissimilaridadeMinima) {
List<Volante> dissimilares = new ArrayList<>(volantes.size());
externo:
for (Volante volante : volantes) {
for (Volante dejaVu : dissimilares) {
if (volante.dissimilaridade(dejaVu) < dissimilaridadeMinima) continue externo;
}
dissimilares.add(volante);
}
return dissimilares;
}
This method gets a list of Volante
s and returns another filtered list by removing those that are too similar to each other. "Too similar" means having a dissimilarity below the specified value with some other steering wheel on the list.
This is the complete code of what I did:
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public final class Combinacoes {
private static final class Volante {
private final Set<Integer> numeros;
public Volante(int[] valores) {
this.numeros = IntStream.of(valores).boxed().collect(Collectors.toCollection(TreeSet::new));
}
public int dissimilaridade(Volante outro) {
List<Integer> interseccao = new ArrayList<>(numeros);
interseccao.removeAll(outro.numeros);
return interseccao.size();
}
@Override
public String toString() {
return numeros.toString();
}
}
public static List<Volante> busca(int quantidade, int numeros) {
List<Volante> volantes = new ArrayList<>();
busca(volantes, new int[quantidade], 0, numeros - quantidade, 0);
return volantes;
}
private static void busca(List<Volante> volantes, int[] resultado, int inicio, int fim, int profundidade) {
for (int x = inicio; x <= fim; x++) {
resultado[profundidade] = x + 1;
if (profundidade + 1 >= resultado.length) {
volantes.add(new Volante(resultado));
} else {
busca(volantes, resultado, x + 1, fim + 1, profundidade + 1);
}
}
}
private static List<Volante> limitarSimilaridade(List<Volante> volantes, int dissimilaridadeMinima) {
List<Volante> dissimilares = new ArrayList<>(volantes.size());
externo:
for (Volante volante : volantes) {
for (Volante dejaVu : dissimilares) {
if (volante.dissimilaridade(dejaVu) < dissimilaridadeMinima) continue externo;
}
dissimilares.add(volante);
}
return dissimilares;
}
public static void main(String[] args) {
List<Volante> volantes = busca(6, 10);
System.out.println(volantes.toString().replace("], ", "]\n"));
System.out.println("Total de combinacoes: " + volantes.size());
List<Volante> filtrados = limitarSimilaridade(volantes, 2);
System.out.println("Tamanho final: " + filtrados.size());
System.out.println("Resultado final");
System.out.println(filtrados.toString().replace("], ", "]\n"));
}
}
As you can see, I made a few other changes to the code besides the ones I listed above. Basically the idea was:
When executing this new program, this is the end of the output (after showing the 210 steering wheels generated):
Tamanho final:18
Resultado final
[[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 7, 8]
[1, 2, 3, 4, 9, 10]
[1, 2, 3, 5, 7, 9]
[1, 2, 3, 5, 8, 10]
[1, 2, 3, 6, 7, 10]
[1, 2, 3, 6, 8, 9]
[1, 2, 4, 5, 7, 10]
[1, 2, 4, 5, 8, 9]
[1, 2, 4, 6, 7, 9]
[1, 2, 4, 6, 8, 10]
[1, 2, 5, 6, 7, 8]
[1, 2, 5, 6, 9, 10]
[1, 2, 7, 8, 9, 10]
[3, 4, 5, 6, 7, 8]
[3, 4, 5, 6, 9, 10]
[3, 4, 7, 8, 9, 10]
[5, 6, 7, 8, 9, 10]]
This is exactly the same list that you put in your question and you hoped to have as an answer.
See here working on ideone.
Your problem is probably simple and easy to solve. However the description you gave got super confused and I didn’t understand anything. I tried to edit it to see if it would make more sense to me (and to others as well). With the edition gave to improve a little, but still do not understand what you are wanting to do.
– Victor Stafusa