使用地图键 - Java从值中选择最高数据

时间:2016-04-29 09:29:57

标签: java date dictionary arraylist

我有一张包含日期和产品发布类型的地图。

示例(" 2015/04/12"," 1 | Prod43");

我的地图值:

2015/08/27  1|Prod23
2015/12/15  1|Prod55
2016/04/08  1|Prod09
2016/04/09  2|Prod09
2016/04/12  3|Prod09

我想维护2个数组列表,dateList包含值,prodList表示值。但约束是,在4月份,Prod09有三个版本,在" |"之前用数字表示。符号。我想要任何月份的产品的最新版本。

这里,April有3个版本,我想只将第3个版本带入我的arrayList。

需要我的arrayList如:

dateList -> ["2015/08/27","2015/12/15","2016/04/12"]
prodList - >["1|Prod23","1|Prod55","3|Prod09"]

代码:

{
Map<String,String> dateMap = new TreeMap<String,String>();
            dateMap.put("2015/08/27","1|Prod23");
            dateMap.put("2015/12/15","1|Prod55");
            dateMap.put("2016/04/08","1|Prod09");
            dateMap.put("2016/04/09","2|Prod09");
            dateMap.put("2016/04/12","3|Prod09");
            String test1="";
            String test2="";
            int count=0;
            List<String> prodList = new ArrayList<String>();
            List<String> dateList = new ArrayList<String>();

            for (Map.Entry<String, String> entry : dateMap.entrySet()) 
                        {   
                            String key = entry.getKey().substring(0,7);
                            String dateValue = entry.getValue();

                            if(("").equals(test1)){
                                test1=key;
                                test2=key;
                            }
                            if(!(test2.equals(key))){
                                dateList.add(key);
                                prodList.add(dateValue);
                                test2=key;
                            }else{
                                if(count<1){
                                dateList.add(key);
                                prodList.add(dateValue);
                                test2=key;
                                count++;
                                }
                            }

                        }
                    System.out.println("dateList: "+dateList);
                    System.out.println("prodList: "+prodList);
}

在上面的方法中,我已经完成了查找第二个最新版本的最大值,但如果版本增加,这种方法将失败。任何人都可以建议我更好的方法来做到这一点。非常感谢你的帮助。

4 个答案:

答案 0 :(得分:3)

夫妻观察:

  • 您与&#34; |&#34;的串联字符显示您尝试将2个数据保存在单个值中。 (这是不好的信息练习,如果你真的需要两者,而是为每个值创建一个带有字段的新类。或者你可以使用列表的索引作为相对排名的隐含值,如下所示)。
  • 地图(和其他数据结构)可以保留任何对象,包括java.util.Date(或其中一个更现代的时间类),数组,List等。
  • 目前尚不清楚为什么要将日期映射到产品发布。

出于您的问题的目的,类似于以下地图的结构可能更有用:

{Product =&gt; [ReleaseDate1,ReleaseDate2,...]}

产品可能是&#34; Prod23&#34;,&#34; Prod55&#34;,&#34; Prod09&#34;等等,地图的值将是List或数组,可能为空。 (List更容易添加)。

要获取&#34; Prod12&#34;的最新版本的日期,您可以执行以下操作:

dates = prodMap.get("Prod12");
lastDate = dates.get(dates.size()); // assuming they where inserted in order

有分类的集合(或者你可以提供一个比较器)来确保集合的顺序。

答案 1 :(得分:2)

由于您使用的TreeMap是根据其键的自然顺序排序的,因此我们可以使用此属性编写一些代码。我可以快速提出这段代码,也许它可以帮助你

Map<String, String> dateMap = new TreeMap<String, String>();
dateMap.put("2015/08/27", "1|Prod23");
dateMap.put("2015/12/15", "1|Prod55");
dateMap.put("2016/04/08", "1|Prod09");
dateMap.put("2016/04/12", "3|Prod09");
dateMap.put("2016/04/09", "2|Prod09");

String lastKey = "";
String currentKey = "";
List<String> date = new ArrayList<String>();
List<String> release = new ArrayList<String>();
for(Map.Entry<String, String> entry : dateMap.entrySet()) {
    String temp = entry.getKey();
    currentKey = temp.substring(0, 7);
    if(currentKey.equals(lastKey)){ // another release in same month as previous release
        // Remove last release details
        date.remove(date.size() - 1);
        release.remove(release.size() - 1);
        // Add current release deetails
        date.add(temp);
        release.add(entry.getValue());
        lastKey = currentKey;
    } else { // first release in this month
        // Add current release deetails
        date.add(temp);
        release.add(entry.getValue());
        lastKey = currentKey;
    }
}

也许你的代码提出了更精致的版本。以下是上述代码的输出

[2015/08/27, 2015/12/15, 2016/04/12]
[1|Prod23, 1|Prod55, 3|Prod09]

答案 2 :(得分:0)

我不打算创建一个String列表来保留日期,而是希望准备一份Date列表。除非您使用相同的格式,否则将String转换为Date并不困难。

这将有助于您转换问题代码中提供的当前格式。

        DateFormat format  = new SimpleDateFormat("yyyy/MM/dd", Locale.ENGLISH);
        Date       date   = format.parse("2016/04/26");

此功能可帮助您从任意数量的提供日期中获取最新日期。

    public static Date findLatest (Date... dates) {
        Date date = dates[0];
        for (int i = 1; i < dates.length; i++) {
            if (dates[i].after(date)) {
                date = dates[i];
            }
        }
        return date;
    }

答案 3 :(得分:0)

问题重新定义

本课题的作者在this Answer的评论中重新定义了问题陈述。只需要每个产品的最新日期。

java.time

Java 8及更高版本包含java.time框架。这些日期时间类取代了设计糟糕且麻烦的旧日期时间类,例如java.util.Date/.Calendar。新类包括LocalDate表示仅限日期的值,YearMonth类可以方便地按整月而不是单个日期组织数据。

将产品代码映射到日期

鉴于已修订的问题,请跟踪每个产品的最新日期,我们需要一个Map,其中产品代码是关键,最新日期LocalDate是值。

Map< String , LocalDate > map = new HashMap<>();

如果您可以将输入数据用于日期的标准ISO 8601格式,我们可以非常简单地输入数据。

map.put( "Prod23" , LocalDate.parse( "2015-08-27" ) );
map.put( "Prod55" , LocalDate.parse( "2015-12-15" ) );
map.put( "Prod09" , LocalDate.parse( "2016-04-08" ) );

现在我们要为同一个Prod09密钥设置一个不同的,更新的日期。 Map将新值(LocalDate替换为“2016/04/09”)替换以前的值(LocalDate为“2016-04-08”)。引用Map::put的文档:

  

如果地图以前包含该键的映射,则旧值将替换为指定的值。

map.put( "Prod09" , LocalDate.parse( "2016-04-09" ) );

并在4月12日晚些时候更换它。

map.put( "Prod09" , LocalDate.parse( "2016-04-12" ) );

mergeput

到目前为止,这种方法假定传入的数据总是用于以后的日期,按时间顺序到达。如果数据可能包含较早的日期,但我们总是希望保留最新日期,那么我们就会遇到问题。为了看到这个问题,我们可以切换两条线,在12日之后放置4月9日。

// Calling `put` with dates arriving *not* in chronological-order.
Map< String , LocalDate> mapP = new HashMap<> ();

mapP.put ( "Prod23" , LocalDate.parse ( "2015-08-27" ) );
mapP.put ( "Prod55" , LocalDate.parse ( "2015-12-15" ) );
mapP.put ( "Prod09" , LocalDate.parse ( "2016-04-08" ) );
mapP.put ( "Prod09" , LocalDate.parse ( "2016-04-12" ) );
mapP.put ( "Prod09" , LocalDate.parse ( "2016-04-09" ) );

System.out.println ( "mapP: " + mapP );

你可以在输出中看到第9个替换了第12个,而不是我们想要的。

  

mapP:{Prod23 = 2015-08-27,Prod55 = 2015-12-15,Prod09 = 2016-04-09}

修复是定义每次我们尝试添加Map时要应用的比较函数。 Map接口为此目的定义了merge方法,我们传递了BiFunction的实现。听起来很奇特,但实际上很容易实现。使用ternary operator的一行代码,在Java 8及更高版本中的一些Lambda syntax新内容中。

我们定义我们的BiFunction来比较一对LocalDate个对象,并返回较晚的对象(isAfter另一个)。如果相同,那么我们返回哪个都无关紧要。

我们已定义BiFunction,我们会在Map上致电merge而不是put

// Calling `merge` with dates arriving *not* in chronological-order.
Map< String , LocalDate> mapM = new HashMap<> ();

BiFunction<LocalDate , LocalDate , LocalDate> latestLocalDate = ( ld1 , ld2 ) -> {
    return ( ld1.isAfter ( ld2 ) ? ld1 : ld2 );
};

mapM.merge ( "Prod23" , LocalDate.parse ( "2015-08-27" ) , latestLocalDate );
mapM.merge ( "Prod55" , LocalDate.parse ( "2015-12-15" ) , latestLocalDate );
mapM.merge ( "Prod09" , LocalDate.parse ( "2016-04-08" ) , latestLocalDate );
mapM.merge ( "Prod09" , LocalDate.parse ( "2016-04-12" ) , latestLocalDate );
mapM.merge ( "Prod09" , LocalDate.parse ( "2016-04-09" ) , latestLocalDate );

System.out.println ( "mapM: " + mapM );

在此输出中,您可以看到第9个替换了4月12日。第9个被忽略了,第12个被保留了,作为Prod09密钥的最新值。

  

mapM:{Prod23 = 2015-08-27,Prod55 = 2015-12-15,Prod09 = 2016-04-12}

格式化模式

要解析问题中显示的输入数据,请定义DateTimeFormatter对象,然后转入对parse的调用。

DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyy/MM/dd" );
… LocalDate.parse( "2015/08/27" , formatter ) …