【问题标题】:Java perform filter and group and perform media with 2 listJava执行过滤器和分组并使用2个列表执行媒体
【发布时间】:2021-02-27 19:57:27
【问题描述】:

我有两个列表,我想知道如何在 Java 中合并它们,但是通过相等项目的分组、属性的媒体以及根据 id 从新列表中添加项目

我的清单

  List<NotasMateria> notasMaterias = repository.findAll(Sort.by("dataNota").descending());
  List<Materia> materias = materiaRepository.findAll();

你现在好吗

列表1

 {
        "idMateria": 9,
        "idUsuario": 7,
        "materia": "PT",
    },
     {
        "idMateria": 7,
        "idUsuario": 7,
        "materia": "IN"
    },
     {
        "idMateria": 4,
        "idUsuario": 7,
        "materia": "YU"
    }

列表2

 {
    "idNotaMateria": 5,
    "idMateria": 7,
    "idUsuario": 7,
    "notaMateria": 8.0,
    "tipoNota": "winx"
},
{
    "idNotaMateria": 2,
    "idMateria": 11,
    "idUsuario": 7,
    "notaMateria": 2.0,
    "tipoNota": "winx"
},
    {
    "idNotaMateria": 4,
    "idMateria": 11,
    "idUsuario": 7,
    "notaMateria": 2.0,
    "tipoNota": "Net"
}
    

结果

        {
        "idNotaMateria": 2,
        "idMateria": 11,
        "idUsuario": 7,
        "notaMateria": 5.0,  (avarege with notaMateria)
        "tipoNota": "winx",   (gruoping to tipoNota)
        "materia": "IN"        (add camp condition list2.idMateria =list1.idMateria)

    },
        {
        "idNotaMateria": 4,
        "idMateria": 7,
        "idUsuario": 7,
        "notaMateria": 2.0,   (avarege with notaMateria)
        "tipoNota":"Net",     (gruoping to tipoNota)
        "materia": "PT"    (add camp condition list2.idMateria =list1.idMateria)
}

【问题讨论】:

  • 不清楚您要完成什么。
  • 我需要获取两个列表进行合并,将一个列表中的项目添加到另一个列表中,并执行列表值的算术媒体

标签: java lambda java-stream


【解决方案1】:

这里可能需要实现几个类来表示中间键、值和最终结果。

假设初始对象描述如下(使用 Lombok):

@Data
@AllArgsConstructor
class NotasMateria {
    private int idUsuario;
    private int idMateria;
    private int idNotaMateria;
    private double notaMateria;
    private String tipoNota;
}

@Data
class Materia {
    private int idUsuario;
    private int idMateria;
    private String materia;
}

那么Materia 的列表应该被转换成一个映射,其键由int 字段组成:

Map<List<Integer>, String> mapMateria = materias.stream()
        .collect(Collectors.toMap(
            m -> Arrays.asList(m.getIdUsuario(), m.getIdMateria()),
            Materia::getMateria,
            (m1, m2) -> m1 // resolve conflicts in case of any duplicates
        ));

那么Result合并平均notaMateria和最小idNotaMateria的列表可以使用Collectors.collectingAndThen构建:

List<Result> result = notasMaterias.stream()
        .filter(nm -> mapMateria.containsKey(
            Arrays.asList(nm.getIdUsuario(), nm.getIdMateria())
        ))
        .collect(Collectors.groupingBy(
            nm -> new KeyResult(nm.getIdUsuario(), nm.getIdMateria(), nm.getTipoNota()),
            Collectors.collectingAndThen(
                Collectors.toList(),
                list -> {
                    double avgNotaMateria = list.stream()
                            .mapToDouble(NotasMateria::getNotaMateria)
                            .average().getAsDouble();
                    int minIdNotaMateria = list.stream()
                            .mapToInt(NotasMateria::getIdNotaMateria).min().getAsInt();
                    return new ValueResult(avgNotaMateria, minIdNotaMateria);
                }
            )
        )) // intermediate Map<KeyResult, ValueResult>
        .entrySet().stream()
        .map(e -> new Result(
            e.getKey(), 
            e.getValue(), 
            mapMateria.get(Arrays.asList(
                e.getKey().getIdUsuario(), 
                e.getKey().getIdMateria()
            ))
        ))
        .collect(Collectors.toList());

中间 DTO 可能如下所示:

@Data
@AllArgsConstructor
class KeyResult {
    private int idUsuario;
    private int idMateria;
    private String tipoNota;
}

@Data
@AllArgsConstructor
class ValueResult {
    private double avgNotaMateria;
    private int minIdNotaMateria;
    }

@Data
class Result extends NotasMateria {
    private String materia;
    
    public Result(KeyResult key, ValueResult value, String materia) {
        super(
            key.getIdUsuario(), key.getIdMateria(), 
            value.getAvgNotaMateria(), value.getMinIdNotaMateria(),
            key.getTipoNota()
        );
        this.materia = materia;
    }
}

注意:此代码未经编译和测试,因此可能包含拼写错误/小错误。

【讨论】:

  • 需要更改 NotesMateria 实体吗?这里Result error中有一个错误:Cannot resolve method 'super(int, int, double, int, java.lang.String)
  • 不,您不必更改NotesMateria 实体。如果Result 扩展NotesMateria,则应通过调用super() 重用超类的构造函数。如果实际的NotesMateria 实现缺少全参数构造函数,则可以调用默认的无参数构造函数,然后单独设置父类的字段(例如,通过设置器)。另一种选择是将字段从NotesMateria复制到Result,删除extends并独立构建Result,尽管这可能被视为代码重复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
  • 2021-11-05
  • 2019-09-22
  • 2014-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多