Java 8 - Grupo uma lista e encontrar a contagem

esvaziar:

Eu tenho uma lista de resultado. Eu preciso encontrar os resultados passados ​​contar. Mas há uma relação entre alguns itens na lista. Por exemplo. Tenho lista como

1.0 - false
2.0 - true
3.0 - false
4.0 - true
1.1 - true
3.1 - true

Em seguida, a contagem passou deve ser 2 e não a 4. Porque eu quero grupo da lista com base no id (1,1.2,1.3,1.xx no grupo single) e marcá-lo como passagem se todos os artigos do grupo é passar. Tenho grupo tentou usar groupingBye eu tenho um mapa do meu comportamento esperado. I pode iterar o mapa e obter a contagem. Mas eu quero saber se existe alguma maneira eu posso fazer isso simplesmente usando Java 8.

public class Main {

static class Resultx {

    double id = 1;

    Boolean passed = false;

    public void setId(double id) {
        this.id = id;
    }

    public double getId() {
        return id;
    }

    public void setAsPassed() {
        this.passed = true;
    }

    public Boolean getPassed() {
        return passed;
    }

    @Override
    public String toString() {
        return getId() + " - " + getPassed();
    }
}


public static void main(String[] args) {
    List<Resultx> results = new ArrayList<>();
    for (int i = 1; i < 5; i++) {
        Resultx result = new Resultx();
        result.setId(i);
        if (i % 2 == 0) {
            result.setAsPassed();
        }
        results.add(result);
    }
    for (int i = 1; i < 5; i += 2) {
        Resultx result = new Resultx();
        result.setId(i + .1);
        result.setAsPassed();
        results.add(result);
    }
    System.out.println(results.size());
    results.forEach(System.out::println);
    System.out.println(results.stream().filter(Resultx::getPassed).count());
    System.out.println(results.stream().filter(e -> !e.getPassed()).count());
    System.out.println(results.stream().collect(Collectors.groupingBy(r -> (int) (r.getId()))));
}
}

Resultado

Total count - 6
1.0 - false
2.0 - true
3.0 - false
4.0 - true
1.1 - true
3.1 - true
Total pass count  - 4
Total fail count - 2
{1=[1.0 - false, 1.1 - true], 2=[2.0 - true], 3=[3.0 - false, 3.1 - true], 4=[4.0 - true]}

Quero contagem geral passagem e global falhar contagem. que é 2 e dois

Holger:

Há algumas coisas estranhas sobre seu código, como o uso de um doubleID, que você acabou de lançar a intsua operação de agrupamento ou usando um Booleanpara você passedpropriedade em vez de apenas boolean. Usando o tipo de referência Boolean, abre a oportunidade de ser null, o que você teria que pega, se esta possibilidade se destina. Caso contrário, basta utilizar boolean.

Também não está claro, o que resultará realmente querem. O exemplo não é suficiente para descrever.

Se você só quer contar os grupos, onde truesignifica “todos onde a verdadeira” e falsesignifica “em algum lugar false”, você pode fazê-lo tão simples quanto

Map<Boolean,Long> counts = results.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.toMap(r -> (int)r.getId(), Resultx::getPassed, Boolean::logicalAnd),
        m -> m.values().stream()
            .collect(Collectors.partitioningBy(b -> b, Collectors.counting()))
    ));

Se você quiser contar os elementos dos grupos, torna-se mais complicado.

int totalPassedCount = results.stream()
    .collect(Collectors.collectingAndThen(Collectors.groupingBy(r -> (int)r.getId(),
        Collector.of(() -> new Object() { int count = 0; boolean pass = true; },
            (o, r) -> { o.count++; o.pass &= r.getPassed(); },
            (x, y) -> { x.count += y.count; x.pass &= y.pass; return x; },
            o -> o.pass? o.count: 0
        )),
        (Map<Integer,Integer> x) -> x.values().stream().mapToInt(i -> i).sum()
    ));
System.out.println(totalPassedCount);

Este utiliza um coletor de costume como a jusante coletor para groupingBy. Esta coleta coletor costume em um objeto mantendo a contagem de elementos e se todos os elementos passaram, então, em uma etapa de acabamento, ele substitui estes objeto com a contagem, se todos os elementos do grupo passou ou zero se não. Em seguida, uma etapa de acabamento é adicionado ao groupingBycoletor que irá resumir todos esses valores.


solução acima é para obter as contagens passadas, como você pediu no início da sua pergunta. Desde que você está pedindo para os dois no final, você poderia usar

Map<Boolean,Integer> counts = results.stream()
    .collect(Collectors.collectingAndThen(Collectors.groupingBy(r -> (int)r.getId(),
        Collector.of(() -> new Object() { int count = 0; boolean pass = true; },
            (o, r) -> { o.count++; o.pass &= r.getPassed(); },
            (x, y) -> { x.count += y.count; x.pass &= y.pass; return x; }
        )),
        m -> m.values().stream().collect(
            Collectors.partitioningBy(o -> o.pass, Collectors.summingInt(o -> o.count)))
    ));

para obter ambos.

Ou, como é complicado para obter a regra destina-se a partir de um único exemplo,

Map<Boolean,Integer> counts = results.stream()
    .collect(Collectors.collectingAndThen(Collectors.groupingBy(r -> (int)r.getId(),
        Collector.of(() -> new Object() { int passed, failed; },
            (o, r) -> { if(r.getPassed()) o.passed++; else o.failed++; },
            (x, y) -> { x.passed += y.passed; x.failed += y.failed; return x; }
        )),
        m -> m.values().stream()
            .filter(o -> o.passed == 0 || o.failed == 0)
            .collect(Collectors.partitioningBy(o -> o.failed==0,
                Collectors.summingInt(o -> o.failed==0? o.passed: o.failed)))
    ));

isso só vai contar passede failed, se todos os elementos de um grupo passou ou falhou. Mas desde que você disse, você esperaria 2e 2, você pode remover a .filter(o -> o.passed == 0 || o.failed == 0)linha. Então, ele vai contar passedapenas se todos os elementos dos grupos passaram, mas contar tudo failed, mesmo quando alguns elementos do grupo passou. Então, você deseja obter 2e 2como resultado.

Acho que você gosta

Origin http://43.154.161.224:23101/article/api/json?id=185698&siteId=1
Recomendado
Clasificación