Organize groups

Asked

Viewed 197 times

3

I couldn’t find the logic to implement this.

So I’ll explain it another way for better understanding:

The algorithm combines 10 numbers in sets of 6, which gives a total of 210 flywheels. Being that, I need to put a condition to ensure that do not show sets in which repeat 5 of the 6 numbers.

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 always repeat. So I need the algorithm to show me only 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 quantidade = 6;  
    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){  

        if ( (profundidade + 1) >= quantidade)  
            for(int x = inicio; x <= fim; x++){  
                resultado[profundidade] = numeros[x];  
                // faz alguma coisa com um dos resultados possiveis  
                count++;  

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

    private void parsearListaGerada(){
        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());
            System.out.println("Resultado final");
            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); 
        comb.parsearListaGerada();

    }  

}
  • 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.

1 answer

2

Simplifying the code

Let’s take a look at your code.

  1. 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.

  2. 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<>();
    
  3. 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);
    
  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 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.

  5. 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) {
    
  6. 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);
    
  7. 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;
    
  8. We can simplify your if with both fors:

           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.
                }
            }
    
  9. 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.

  10. We can trade quantidade for resultado.length, and thereby eliminate this variable.

  11. 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.

  12. 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.

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

  14. 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 Volantes 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:

  • Leave useful fields only in the method busca live only within this method.

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

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.

  • Thank you very much, I will make an analysis more seems correct.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.