迭代Java集合时最小化复杂性的算法

迭代Java集合时最小化复杂性的算法,java,algorithm,collections,sonarqube,time-complexity,Java,Algorithm,Collections,Sonarqube,Time Complexity,我有一个场景,当我有一个对象列表时,让我们假设: List<A> listofAElements 列表元素 对象有3个字段startDate、endDate和rate。 需求在这个列表上迭代,每当我找到两个具有相同startDate和endDate的元素时,我应该在列表中只保留一个rate=rate1+rate2的元素 这是我做的简单代码,但Sonar抱怨它的复杂性: public static void arrangeList(List<TauxPeriodesA

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

List<A> listofAElements
列表元素
对象有3个字段startDate、endDate和rate。 需求在这个列表上迭代,每当我找到两个具有相同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);
                    }

            }

        }

    }
}
publicstaticvoidarrangelist(列表tauExperiodesAttTos){
对于(int i=0;i=0;j--){
如果(j!=i){
布尔值isStartDatesEquals=TauxPeriodeSatTos.get(i).GetDateFirst().equals(TauxPeriodeSatTos.get(j).GetDateFirst());
布尔值isEndDatesEquals=tauxPeriodesATDtos.get(i).getDateFin().equals(tauxPeriodesATDtos.get(j).getDateFin());
if(isStartDatesEquals和&isEndDatesEquals){
BigDecimal itauxPrime=tauxperiodesadtos.get(i).gettauxprimet();
BigDecimal jTauxPrime=tauxperiodesadtos.get(j.gettauxprimet();
BigDecimal-sommeDesTaux=itauxPrime.add(jTauxPrime);
tauxperiodesadtos.get(i).setTauxPrimeAT(sommeDesTaux);
tauxperiodesadtos.移除(j);
}
}
}
}
}

你有什么更好的建议吗?

如果你使用一个
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() );
//Pair是org.apache.commons.lang3.tuple.Pair,您还可以提供自己的类
组合映射=新LinkedHashMap();
for(tauxperiodesadto元素:tauxperiodesadtos){
Pair key=Pair.of(element.getDateFirst(),element.getDateFin());
tauxperiodesadto existing=combined.get(key);
if(现有!=null){
//重复项已存在,因此请将两者合并
existing.settauxprimet(existing.gettauxprimet().add(element.gettauxprimet());
}否则{
//还没有副本
组合。放置(键、元素);
}      
}
//由于使用LinkedHashMap,元素的顺序应该保留
List resultList=newarraylist(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() );
LinkedHashMap combined=tauxperiodesadtos.stream().collect(
Collectors.toMap((element)->Pair.of(element.getDateFanch(),element.getDateFin()),//创建密钥
Function.identity(),//只需使用新元素
(e,n)->{e.settauxprimet(e.gettauxprimet().add(n.gettauxprimet());返回e;},//组合元素并返回现有元素
LinkedHashMap::new));//使用LinkedHashMap
List resultList=newarraylist(combined.values());

我的想法是你的目标(结合开始和结束日期相同的目标速率),这可以通过基本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;
    }

}
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);
            }

        });
    }

}
MainApp.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;
    }

}
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);
            }

        });
    }

}
package com.stack;
导入java.text.ParseException;
导入java.text.simpleDataFormat;
导入java.util.ArrayList;
导入java.util.Date;
导入java.util.HashMap;
导入java.util.List;
导入java.util.Map;
公共类MainApp{
公共静态void main(字符串[]args)引发异常{
//TODO自动生成的方法存根
Map contains=new HashMap();
列表=新的ArrayList();
ProductVo productVo1=新ProductVo();
productVo1.setStartDate(新的SimpleDateFormat(“dd/MM/yyyy”).parse(“01/10/2017”);
productVo1.setEndDate(新的SimpleDateFormat(“dd/MM/yyyy”).parse(“02/10/2017”);
产品VO1.设定值(10);
列表。添加(productVo1);
ProductVo productVo2=新ProductVo();
productVo2.setStartDate(新的SimpleDateFormat(“dd/MM/yyyy”).parse(“04/10/2017”);
productVo2.setEndDate(新的SimpleDateFormat(“dd/MM/yyyy”).parse(“04/10/2017”);
产品VO2.设定值(20);
列表。添加(productVo2);
ProductVo productVo3=新ProductVo();
productVo3.setStartDate(新的SimpleDateFormat(“dd/MM/yyyy”).parse(“01/10/2017”);
productVo3.setEndDate(新的SimpleDateFormat(“dd/MM/yyyy”).parse(“02/10/2017”);
产品VO3.设定值(30);
列表。添加(productVo3);
列表。forEach(v->{
if(contains.containsKey(v.getStartDate())){
productvop=contains.get(v.getStartDate());
如果(p.getEndDate().equals(v.getEndDate())){
System.out.println(v.getRate()+p.getRate());
}
}
如果(!contains.containsKey(v.getStartDate())){
contains.put(v.getStartDate(),v);
}
});
}
}

Sonar可能会抱怨,因为函数中有3个以上的
if、for、while、else
。我建议您看看是否可以减少循环或if条件。或者使用java的流API重构代码不幸的是,我们使用的是java 7,我首先考虑对列表进行排序,然后将每个元素与下一个元素进行比较但它也是o(n2)colmexity。感谢您提供的解决方案。如果您不想使用外部库,它将非常有效-您可以通过在Tauxperiodesadto中实现自己的equals和hashcode来编写类似的解决方案,以比较日期。@younesmati对