Tengo una lista de cadenas sin clasificar, donde las entradas son una de {A,B,C,D} :
List<String> strings = new ArrayList<>(Arrays.asList("A","C","B","D","D","A","B","C","A","D","B","D","A","C"));Necesito clasificarlos / (agruparlos) en un orden personalizado tomando un elemento a la vez para obtener un resultado como:
[A, B, C, D, A, B, C, D, A, B, C, D, A, D]Estoy luchando para llegar a una idea de cómo hacerlo. ¿Alguna ayuda?
Intenté usar un Comparator<String> personalizado pero no pude implementar la lógica de que la first A < second A y first D < second A .
También probé Stream. groupingBy :
Collection<List<String>> coll = strings.stream().collect(Collectors.groupingBy(s -> s)).values();que agrupa las mismas cadenas en grupos.
[[A, A, A, A], [B, B, B], [C, C, C], [D, D, D, D]]Pero no estoy seguro de cómo tomar un elemento a la vez de las listas anteriores hasta que no haya elementos disponibles. ¿Alguien tiene algún enfoque sobre cómo proceder aquí? Necesita una pista en la dirección correcta.
Crear una lista completamente nueva podría conducir a otras soluciones, por ejemplo:
Map<String, Long> counts = strings.stream().collect(groupingBy(identity(), TreeMap::new, counting())); List<String> ordered = new ArrayList<>(); while (!counts.isEmpty()) { for (Iterator<Map.Entry<String, Long>> it = counts.entrySet().iterator(); it.hasNext(); ) { Map.Entry<String, Long> entry = it.next(); ordered.add(entry.getKey()); long newCount = entry.getValue() - 1; if (newCount == 0) { it.remove(); } else { entry.setValue(newCount); } } } Con strings siendo la lista de entrada y ordered la salida.
Agregue un prefijo numérico a cada valor, ordene y elimine el prefijo, con limitación, el tamaño de la matriz no puede ser mucho mayor que el prefijo numérico
List<String> strings = new ArrayList<>(Arrays.asList("A","C","B","D","D","A","B","C","A","D","B","D","A","C")); Map<String, Integer> m = new HashMap<>(); strings.stream() .map(i -> String.format("%dx%s", (100000 + m.merge(i, 1, (n, w) -> n+w)), i)) .sorted() .map(i -> i.replaceFirst("^\\d+x", "")) .collect(Collectors.toList());Esta es aproximadamente la misma lógica que la respuesta de sp00m , pero implementada con dos flujos:
Map<String, Long> groups = strings.stream() .collect(Collectors.groupingBy(Function.identity(), TreeMap::new, Collectors.counting())); List<String> result = IntStream.range(0, groups.values().stream() .mapToInt(Long::intValue).max().orElseThrow()) .mapToObj(c -> groups.keySet().stream().filter(k -> groups.get(k) > c)) .flatMap(Function.identity()) .collect(Collectors.toList()); TreeMap se encarga de la clasificación. Solo asegúrese de que los elementos de su lista real sean comparables (o que proporcione el proveedor correcto de TreeMap)