# java – Organize groups

## Question:

I couldn't find the logic to implement this.

So, I'll explain it another way for better understanding:

The algorithm combines 10 numbers into sets of 6, which gives a total of 210 wheels. Since, I need to put a condition to ensure that they don't show sets in which 5 of the 6 numbers are repeated.

Example: I have this combination 10 numbers in a set of 6.

``````1 2 3 4 5 6  //
1 2 3 4 5 7
1 2 3 4 5 8
1 2 3 4 5 9
1 2 3 4 5 10
1 2 3 4 6 7
1 2 3 4 6 8
1 2 3 4 6 9
1 2 3 4 6 10
1 2 3 4 7 8  //
.......
``````

Since, 5 of the 6 numbers in the set are always repeated. So I need the algorithm to show me only the sets that don't have the 5 repeated numbers. As I highlighted with `//` .

``````01  02  03  04  05  06 ;
01  02  03  04  07  08 ;
01  02  03  04  09  10 ;
01  02  03  05  07  09 ;
01  02  03  05  08  10 ;
01  02  03  06  07  10 ;
01  02  03  06  08  09 ;
01  02  04  05  07  10 ;
01  02  04  05  08  09 ;
01  02  04  06  07  09 ;
01  02  04  06  08  10 ;
01  02  05  06  07  08 ;
01  02  05  06  09  10 ;
01  02  07  08  09  10 ;
03  04  05  06  07  08 ;
03  04  05  06  09  10 ;
03  04  07  08  09  10 ;
05  06  07  08  09  10 ;
``````
``````package jogo;

import java.awt.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

public class Combinacoes {

private int numeros[] = {1,2,3,4,5,6,7,8,9,10};
private int resultado[] = new int[6];
private ArrayList<String>aParsear = new ArrayList<String>();
private HashMap<Integer,String> map = new HashMap<Integer,String>();
private int count = 0;
private String[] temp;

private void busca(int inicio,int fim, int profundidade){

for(int x = inicio; x <= fim; x++){
// faz alguma coisa com um dos resultados possiveis
count++;

String tmp = ""+  resultado[0] + ", "
System.out.println(tmp);
}
else
for(int x = inicio; x <= fim; x++){
busca(x + 1,fim + 1,profundidade + 1);
}
}

Iterator<String> it = aParsear.iterator();

while(it.hasNext()){
String tmp = it.next();
int[]valoresInteiros = new int[6];
String[]valoresLiterais = tmp.split(",");
for(int i = 0;i < valoresLiterais.length;i++){
valoresInteiros[i]= Integer.parseInt(valoresLiterais[i].trim());
}
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());
for(String valor:map.values())
System.out.println(valor);

}

public static void main(String args[]){

Combinacoes comb = new Combinacoes();
comb.busca(0, (10-6), 0);
System.out.println("Total de combinacoes: " + comb.count);

}

}
``````

# Simplifying the code

Let's take a look at your code.

1. See this import:

` `import java.awt.List;``

This is not the list you want to import. You're not using this `List` for anything, but what you actually wanted to import is `java.util.List` .

2. These variables:

`` private ArrayList<String>aParsear = new ArrayList<String>(); private HashMap<Integer,String> map = new HashMap<Integer,String>();``

You can use diamond syntax to avoid having to repeat generics. Also, it is good practice to code for an interface and not an implementation. That is, using `List` and `Map` (from the `java.util` package) as types instead of `ArrayList` and `HashMap` . Here's what the result would be:

`` private List<String> aParsear = new ArrayList<>(); private Map<Integer, String> map = new HashMap<>();``
3. Let's see how you transform the array into a `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 did, and it doesn't depend 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 a problem with changing the format of the resulting `String` a bit:

`` String tmp = Arrays.toString(resultado);``
4. 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's very easy for you to mess up by not putting them. For example:

` `if (algumaCoisa) System.out.println("Estou dentro do if."); System.out.println("Será que ainda estou dentro do if?");``

In fact, below, 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. The indentation suggests that the `}` refers to the `if` , but it is actually the outside `while` . The fact that the code is incorrectly indented and does not use all the key pairs that it should end up inducing whoever is reading the code to error.

5. See your `while` loop:

`` Iterator<String> it = aParsear.iterator(); while(it.hasNext()){ String tmp = it.next();``

Don't use the `Iterator` directly if you don't have a good reason to. Prefer enhanced-for :

`` for (String tmp : aParsear) {``
6. Your `aParsear` list actually consists of an array that you change to a `String` and then back to an array. This is a workaround. To solve this, you can change this code:

`` aParsear.add(tmp);``

That's why:

`` aParsear.add(resultado.clone());``

And with that, you can eliminate the `tmp` variable from the `busca` method if you want.

This from here:

`` private ArrayList<String>aParsear = new ArrayList<String>()``

Stays like this:

`` private List<int[]> aParsear = new ArrayList<>();``

You can then simplify a lot of things in `parsearListaGerada` with this:

`` for (int[] valoresInteiros : aParsear) { String tmp = Arrays.toString(valoresInteiros);``
7. You can replace this:

`` System.out.println("Total de combinacoes: " + comb.count);``

That's why:

`` System.out.println("Total de combinacoes: " + comb.aParsear.size());``

And then this here can be deleted:

`` // faz alguma coisa com um dos resultados possiveis count++;``

And that too:

`` private int count = 0; private String[] temp;``
8. We can simplify your `if` with the two `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 like this:

`` for (int x = inicio; x <= fim; x++) { resultado[profundidade] = numeros[x]; if (profundidade + 1 >= quantidade) { // Algumas coisas. } else { // Outras coisas. } }``
9. Note that your `Map` is only used within the `parsearListaGerada` method and that after using the method, the `Map` does not contain any information that is relevant to be preserved. Therefore, put the `Map` as a local variable of this method.

10. We can exchange `quantidade` for `resultado.length` , and thus eliminate that variable.

11. Prefer to use `(String[] args)` instead of `(String args[])` . This way you preserve the declaration pattern [variable type before and variable name after] used almost everywhere else in the Java language. Otherwise there's something in the format [part of the variable's type first, variable name in the middle, rest of the variable's type after], which is a little confusing. The same goes for transforming `int resultado[]` into `int[] resultado` .

12. Assuming the list of numbers is always 1, 2, 3, 4… then you can eliminate the array `numeros` and replace the `numeros[x]` with `x + 1` .

13. A better name for your `aParsear` variable would be `volantes` .

14. To prevent your program from getting stuck on 10 elements in the game with 6 on the wheel and you having to call `comb.buscar(0, (10-6), 0);` in `main` , passing these magic numbers, you can introduce a constructor and a new `busca` method:

`` 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 this:

`` Combinacoes comb = new Combinacoes(6); comb.busca(10);``

There are still a few other changes possible, but I think it's a good size here. The resulting code behaves exactly the same as your original question code (except that it shows pairs of square brackets for every sextuple in the output). See how your code looks like:

# 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 List<int[]> volantes = new ArrayList<>();

}

public void busca(int numeros) {
}

private void busca(int inicio, int fim, int profundidade) {
for (int x = inicio; x <= fim; x++) {
} else {
busca(x + 1, fim + 1, profundidade + 1);
}
}
}

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());
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());
}
}
``````

# improving the code

I don't understand what your idea is with the `chave` and the `Map` , but there are some elements where 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 collisions of these keys occur, showing the 71 places that have them (this is the final size).

Considering that the result you want in the table that is in your question, I don't think that this method's `parsearListaGerada` procedure makes sense for you. If I understand your question correctly, what you want is to eliminate results that have 5 or more repeated numbers. This method however only shows which steering wheels have keys colliding. I ended up throwing this method away.

To redo everything, first let's introduce a `Volante` class:

``````    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));
}

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. Her constructor converts an `int[]` to a `Set<Integer>` . The big thing is the `dissimilaridade(Volante)` method `dissimilaridade(Volante)` which measures how many numbers differ between one wheel and another.

With that, we can do 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) {
}
}
return dissimilares;
}
``````

This method gets a list of `Volante` if it returns another filtered list removing those that are too similar to each other. By "too similar" it is meant that they have a dissimilarity below the specified value with some other wheel in 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));
}

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<>();
return volantes;
}

private static void busca(List<Volante> volantes, int[] resultado, int inicio, int fim, int profundidade) {
for (int x = inicio; x <= fim; x++) {
} else {
}
}
}

List<Volante> dissimilares = new ArrayList<>(volantes.size());

externo:
for (Volante volante : volantes) {
for (Volante dejaVu : dissimilares) {
}
}
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());

}
}
``````

As you can see, I made a few more changes to the code besides the ones I listed above. Basically the idea was:

• Leaving fields useful only in the method `busca` live only within that method.

• Produce lists as a result of methods instead of just storing them.

When running this new program, here is the end of the output (after showing the 210 handwheels generated):

``````Tamanho final:18
[[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 that you were hoping to get an answer.

Scroll to Top