Tengo dos métodos casi idénticos que filtran la lista y devuelven el resultado filtrado. Su algoritmo es idéntico, la diferencia es que la primera función devuelve el elemento más frecuente y la segunda devuelve el menos frecuente:
private static List<List<Character>> filter(List<List<Character>> lines, int charIndex) { List<List<Character>> result = copyList(lines); List<List<Character>> startWith0 = new ArrayList<>(); List<List<Character>> startWith1 = new ArrayList<>(); for(int i = 0; i < result.size(); i++) { List<Character> currentLine = result.get(i); if (currentLine.get(charIndex) == '1') { startWith1.add(currentLine); } else if (currentLine.get(charIndex) == '0') { startWith0.add(currentLine); } } if (startWith1.size() > startWith0.size() || startWith1.size() == startWith0.size()) { return startWith1; } else { return startWith0; } }El final de la segunda función se ve así:
if (startWith1.size() > startWith0.size() || startWith1.size() == startWith0.size()) { return startWith0; } else { return startWith1; }Creo que esta duplicación de código no es un buen diseño de programa pero no veo la buena manera de dividir la primera parte de la función y la segunda en los diferentes métodos.
Tienes pocas opciones.
Cree un método de ayuda (es private , su nombre comienza con el método para el que es un ayudante, aunque en este caso, como es un ayudante para 2, eso podría ser un poco complicado), que hace todo el trabajo y tiene un parámetro de estado que indica cómo hacer la última parte. En este caso, su parámetro de estado puede ser simplemente un boolean . Para otras situaciones similares, a menudo una enumeración (que también puede escribir en el mismo archivo fuente y declarar como private ) es más apropiada.
Este ayudante terminaría en algo como:
boolean winner = startWith1.size() < startWith0.size(); return most == winner ? startWith1 : startWith0; Y su método de filter actual se convierte en una sola línea:
public List<Character> filterMost(List<List<Character>> lines, int charIdx) { return filter(lines, charIdx, true); } private List<Character> filter(List<List<Character>> lines, int charIdx, boolean most) { ... }Puede pasar una función que seleccione qué hacer en función de una entrada de las 2 listas. Efectivamente, es lo mismo que la primera respuesta (todavía involucra métodos de ayuda), pero en lugar de escribir las diferentes rutas de código en el ayudante, las escribe en los métodos reales (pasándoselas al ayudante). Es más complicado pero puede resultar en un código más fácil de mantener. En general, el código 'más corto y menos complejo' siempre gana al código 'más largo, más complejo, pero teóricamente más fácil de mantener', por lo que en este caso dudo que este sea el movimiento correcto. Sin embargo, en los casos en que hay más estados y la parte diferente está más involucrada, esta puede ser la mejor respuesta. Se ve como esto:
public List<Character> filterMost(List<List<Character>> lines, int charIdx) { ... } public List<Character> filterLeast(List<List<Character>> lines, int charIdx) { return filter(lines, charIdx, (list0, list1) -> { if (list0.size() < list1.size()) return list0; return list1; }; } private List<Character> filter(List<List<Character>> lines, int charIdx, BinaryOperator<List<Character>> op) { ... return op.apply(startWith0, startWith1); }En mi humilde opinión, puede eliminar el bucle que está llenando las dos ArrayLists y, por supuesto, dar a ambos métodos nombres autoexplicativos como filerMostFrequent/filterLeastFrequent o algo así:
private static List<List<Character>> filerMostFrequent(List<List<Character>> lines, int charIndex) { List<List<Character>> result = copyList(lines); List<List<Character>> startWith0 = new ArrayList<>(); List<List<Character>> startWith1 = new ArrayList<>(); filter(charIndex, result, startWith0, startWith1); if (startWith1.size() > startWith0.size() || startWith1.size() == startWith0.size()) { return startWith1; } else { return startWith0; } } private static List<List<Character>> filterLeastFrequent (List<List<Character>> lines, int charIndex) { List<List<Character>> result = copyList(lines); List<List<Character>> startWith0 = new ArrayList<>(); List<List<Character>> startWith1 = new ArrayList<>(); filter(charIndex, result, startWith0, startWith1); if (startWith1.size() > startWith0.size() || startWith1.size() == startWith0.size()) { return startWith0; } else { return startWith1; } } private static void filter(int charIndex, List<List<Character>> result, List<List<Character>> startWith0, List<List<Character>> startWith1) { for(int i = 0; i < result.size(); i++) { List<Character> currentLine = result.get(i); if (currentLine.get(charIndex) == '1') { startWith1.add(currentLine); } else if (currentLine.get(charIndex) == '0') { startWith0.add(currentLine); } } }