【问题标题】:Minimizing Complexity algorithm when Iterating on Java Collection迭代 Java 集合时最小化复杂度算法
【发布时间】:2017-10-06 08:48:03
【问题描述】:

当我有一个对象列表时,我有一个场景让我们假设:

List<A> listofAElements

一个对象有 3 个字段 startDate、endDate 和 rate。 需求在此列表上进行迭代,每当我找到 2 个具有相同 startDate 和 endDate 的元素时,我应该只在列表中保留一个 rate = rate1 + rate2。

这是我这样做的简单代码,但 Sonar 抱怨它的复杂性:

    public static void arrangeList(List<TauxPeriodesATDto> tauxPeriodesATDtos){

    for (int i =0 ; i < tauxPeriodesATDtos.size() ; i++  ){

        for (int j = tauxPeriodesATDtos.size() -1 ; j >= 0; j-- ){

            if (j != i){
                    boolean isStartDatesEquals = tauxPeriodesATDtos.get(i).getDateDebut().equals(tauxPeriodesATDtos.get(j).getDateDebut());
                    boolean isEndDatesEquals = tauxPeriodesATDtos.get(i).getDateFin().equals(tauxPeriodesATDtos.get(j).getDateFin());

                    if (isStartDatesEquals && isEndDatesEquals ) {
                        BigDecimal itauxPrime = tauxPeriodesATDtos.get(i).getTauxPrimeAT();
                        BigDecimal jTauxPrime = tauxPeriodesATDtos.get(j).getTauxPrimeAT();
                        BigDecimal sommeDesTaux = itauxPrime.add(jTauxPrime);
                        tauxPeriodesATDtos.get(i).setTauxPrimeAT(sommeDesTaux);
                        tauxPeriodesATDtos.remove(j);
                    }

            }

        }

    }
}

您对更好的方法有什么建议吗?

【问题讨论】:

  • Sonar 可能会抱怨,因为函数中有超过 3 个 if,for,while,else。我建议您查看是否可以减少循环或 if 条件。或者使用 Java 的 Stream API 重构代码

标签: java algorithm collections sonarqube time-complexity


【解决方案1】:

如果您使用 LinkedHashMap 其键是由开始日期和结束日期形成的周期并且其值是元素,您应该能够获得 O(n) 时间复杂度。然后您遍历您的列表,将它们放入地图中,如果这样的元素已经存在,您只需将两者结合起来。

为了更好地理解,我将提供一个非 lambda/流式版本:

//Pair is org.apache.commons.lang3.tuple.Pair, you could also provide your own class
Map<Pair<Date, Date>, TauxPeriodesATDto> combined = new LinkedHashMap<>();

for( TauxPeriodesATDto element : tauxPeriodesATDtos ) {
  Pair<Date, Date> key = Pair.of( element.getDateDebut(), element.getDateFin() );
  TauxPeriodesATDto existing = combined.get( key );

  if( existing != null ) {
    //duplicate already exists, so combine the two
    existing.setTauxPrimeAT( existing.getTauxPrimeAT().add( element.getTauxPrimeAT() );
  } else {
    //no duplicate yet
    combined.put( key, element );
  }      
}

//due to the use of LinkedHashMap the order of elements should be preserved
List<TauxPeriodesATDto> resultList = new ArrayList<>( combined.values() );

Java8 变体可能如下所示:

LinkedHashMap<Pair, Element> combined = tauxPeriodesATDtos.stream().collect( 
       Collectors.toMap( (element) -> Pair.of( element.getDateDebut(), element.getDateFin()), //create the key
                         Function.identity(), //just use the new element
                         (e,n) -> { e.setTauxPrimeAT( e.getTauxPrimeAT().add( n.getTauxPrimeAT() ); return e; }, //combine the elements and return the existing one
                         LinkedHashMap::new ) ); //use a LinkedHashMap

List<TauxPeriodesATDto> resultList = new ArrayList<>( combined.values() );

【讨论】:

  • 不幸的是,我们使用的是 java 7,我首先考虑对列表进行排序,然后将每个元素与下一个元素进行比较,但它也是 o(n2) colmexity。感谢您提供的解决方案,效果很好
  • 如果您想避免使用外部库 - 您可以通过在 TauxPeriodesATDto 中实现自己的等号和哈希码来比较日期,从而编写类似的解决方案。
  • @younesmati 对列表进行排序然后比较应该有 O(n log(n)) 的总体复杂性:排序是 O(n log(n)),迭代和组合是 O(n)。我也考虑过那个解决方案,但我不知道是否应该保留原始顺序并且使用地图进行操作无论如何都是 O(n) (迭代 = O(n),地图访问 = O(1))。
  • @Thomas 是的,我同意排序和比较是 O(nlog(n)),您介绍的解决方案似乎更合适,顺便说一下,在我的情况下,我不需要保留原始订单,所以如果有更好的解决方案,请告诉我!谢谢你的帮助,我很感激
【解决方案2】:

我的想法是你的目标(结合开始和结束日期相同的对象的速率),这可以通过基本的DP来实现。

只需存储每个最后一次迭代并将其与当前迭代进行比较,如果您已经有相似的日期,则合并结果。

下面我分享我试过的例子。

ProductVo.Java

package com.stack;

import java.util.Date;

public class ProductVo {

    private Date startDate;
    private int rate;
    private Date endDate;

    public Date getStartDate() {
        return startDate;
    }

    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    public int getRate() {
        return rate;
    }

    public void setRate(int rate) {
        this.rate = rate;
    }

    public Date getEndDate() {
        return endDate;
    }

    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

}

MainApp.Java

package com.stack;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MainApp {

    public static void main(String[] args) throws ParseException {
        // TODO Auto-generated method stub

        Map<Date, ProductVo> contains = new HashMap<>();
        List<ProductVo> list = new ArrayList<ProductVo>();

        ProductVo productVo1 = new ProductVo();
        productVo1.setStartDate(new SimpleDateFormat("dd/MM/yyyy").parse("01/10/2017"));
        productVo1.setEndDate(new SimpleDateFormat("dd/MM/yyyy").parse("02/10/2017"));
        productVo1.setRate(10);
        list.add(productVo1);

        ProductVo productVo2 = new ProductVo();
        productVo2.setStartDate(new SimpleDateFormat("dd/MM/yyyy").parse("04/10/2017"));
        productVo2.setEndDate(new SimpleDateFormat("dd/MM/yyyy").parse("04/10/2017"));
        productVo2.setRate(20);
        list.add(productVo2);

        ProductVo productVo3 = new ProductVo();
        productVo3.setStartDate(new SimpleDateFormat("dd/MM/yyyy").parse("01/10/2017"));
        productVo3.setEndDate(new SimpleDateFormat("dd/MM/yyyy").parse("02/10/2017"));
        productVo3.setRate(30);
        list.add(productVo3);

        list.forEach(v -> {

            if (contains.containsKey(v.getStartDate())) {

                ProductVo p = contains.get(v.getStartDate());
                if (p.getEndDate().equals(v.getEndDate())) {
                    System.out.println(v.getRate() + p.getRate());
                }
            }

            if (!contains.containsKey(v.getStartDate())) {
                contains.put(v.getStartDate(), v);
            }

        });
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-09
    • 2019-01-26
    • 2021-11-15
    • 2019-05-09
    • 2023-03-24
    • 2023-03-04
    • 2021-01-20
    • 2017-06-04
    相关资源
    最近更新 更多