【问题标题】:Add and compare datetime values in ArrayList of a HashMap in Java在 Java 中的 HashMap 的 ArrayList 中添加和比较日期时间值
【发布时间】:2016-09-08 19:53:06
【问题描述】:

我在 Java 中有一个 String,List<Date> 类型的 HashMap。现在我要做的是为每个键找到总时间(通过在每个日期中添加单独的时间),然后忽略时间最长的键。如果有两个最高时间相同的键,则忽略键小于整数形式的键(键 100 小于 101)。对于其余的键,如果时间小于 3 分钟,我想通过将时间(以秒为单位)乘以 50(因此,如果时间为 00:02:59,则乘以 179 by 50)或超过 3 分钟,则乘以 50 来找到结果成本时间(四舍五入到下一分钟)乘以 80(所以如果时间是 00:03:01 则乘以 4 by 80)。

我拥有的 HashMap 数据示例是:

100 [Thu Jan 01 00:05:01 EST 1970]
101 [Thu Jan 01 00:01:07 EST 1970, Thu Jan 01 00:05:03 EST 1970]
102 [Thu Jan 01 00:07:11 EST 1970]
103 [Thu Jan 01 00:02:59 EST 1970, Thu Jan 01 00:04:38 EST 1970, Thu Jan 01 00:06:16 EST 1970]

在上面的示例中,您可以看到键 103 的时间最长(添加 00:02:5900:04:3800:06:16)所以我将在最终成本计算中忽略此键中的所有值。对于其余的键,我想按照我上面提到的规则计算我的最终成本 - 例如,对于键 101,总成本将是 67*50 (00:01:07 is less than 3 minutes) + 6 * 80 (00:05:03 is more than 3 minutes)

更新:经过一些建议,我目前的代码是:

long totalCost = map.values().stream()
    .mapToLong(dates -> dates.stream().mapToLong(Date::getTime).sum())
    .sorted().limit(map.size() - 1)
    .map(Myclass::getCost).sum();

    System.out.println(totalCost);

此代码的一个问题是,假设如果有两个总时间相同的键,在这种情况下,我想忽略键值数字较小的键(如键 100 小于 101)。到目前为止,代码忽略了排序后的第一个可用键(在sorted().limit(map.size() - 1) 行)。如何修改它以检查是否有多个键具有相同的最大时间而不是忽略具有最小数值的键。

注意:每个值中的日期时间值都有一个日期部分,它与 1970 年 1 月 1 日星期四美国东部标准时间相同,与计算无关。

【问题讨论】:

  • 迭代entryset ...找到最大值并忽略它,并将其余条目存储在另一个映射中...再次迭代并计算成本..就这么简单...跨度>
  • Date 似乎是错误的数据类型。 java.time.Duration 可能是更好的选择。
  • @MichaelMarkidis 我已经更新了我上面的帖子,以表明我现在拥有的代码。
  • @DanglingPiyush 你能用我上面发布的示例数据给我一个例子吗?
  • @user2966197 如果您不知道如何在地图上使用 Entryset,请阅读 java.util.Map 实现。试一试并不难...基本上您可以遍历地图(键和值)使用入口集..我建议自己弄清楚其余的..

标签: java datetime hashmap


【解决方案1】:

正确的类型

您使用了所有错误的数据类型。

Integer

您的 String 类型的键实际上是一个整数,正如您所说,我们应该用数字比较它的值。所以首先使用Integer 类。

Duration

您正在滥用 java.util.Date 类,一个日期时间值,作为时间跨度。首先,完全避免麻烦的旧日期时间类,并使用它们的替代品java.time 类。其次,使用时间跨度类来表示时间跨度。在您的特定情况下,这意味着 java.time.Duration 类。

Duration 类可以解析并生成其在standard ISO 8601 format 中的值的字符串表示形式。例如,PT1M30S 表示“一分半钟”。

避免使用时间格式来表示时间跨度,因为这会产生歧义; ISO 8601 格式易于解析、易于阅读、避免歧义并且专为目的而设计。

不是Map

您对Map 的使用变得很尴尬,因为您实际上是在使用三个值而不是一对:

  • 整数(键、标识符)
  • 列表(时间跨度的集合)
  • 整数(为每个持续时间生成的“成本”值的总和)

自定义类

所以用这三个值创建一个类。最后一个是只读值,可以即时计算或缓存以获得更好的性能。

这是一个示例类。我将其命名为Event,因为问题中没有给出名称。注意:使用此源代码完全由您自担风险。不是线程安全的。未测试。不以任何方式保证。

此类动态重新计算其Duration 对象列表的开销。缓存会在大量使用或处理大量数据时提高性能。

此类使用自定义方法实现Comparable,该方法说明了比较成本的主要规则,然后在成本相等的情况下比较id号。

成为Comparable 意味着您可以轻松地对这些Event 对象的集合进行排序。然后忽略第一项/最后一项来处理您忽略最高得分事件的规则。

package example;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * Example class posted on Stack Overflow:
 * http://stackoverflow.com/q/39399156/642706
 *
 * Caution: NOT thread-safe. NOT tested. NOT guaranteed.
 *
 * © 2016 Basil Bourque. This source code may be used in accordance with the ISC
 * license: https://opensource.org/licenses/ISC
 *
 * @author Basil Bourque.
 */
public class Event implements Comparable<Event> {

    private Integer id;
    private List<Duration> durations;

    // Constants
    static final public long COST_PER_SECOND = 50L;
    static final public long COST_PER_MINUTE = 80L;

    // Constructor.
    public Event ( Integer id , List<Duration> durations ) {
        this.id = id;
        this.durations = durations;
    }

    public Integer getId () {
        return this.id;
    }

    public List<Duration> getDurations () {
        List<Duration> defensiveCopyOfList = new ArrayList<> ( this.durations );
        return defensiveCopyOfList;
    }

    public Long getCost () {
        // Calculate the cost of each Duration in our list.
        // Perhaps cache this calculated value for better performance.
        long sum = 0;
        for ( Duration duration : this.durations ) {
            long c = this.calculateCostOfDuration ( duration );
            sum = ( sum + c );
        }
        return sum;
    }

    private long calculateCostOfDuration ( Duration duration ) {
        long result = 0;
        long countMinutes = duration.toMinutes ();
        long limit = 3L; // We care if the duration is under 3 minutes (or else is 3 or more minutes).
        if ( countMinutes < limit ) {
            result = ( duration.getSeconds () * Event.COST_PER_SECOND );
        } else if ( countMinutes >= limit ) {
            // Round up to next minute. If ane even multiple of 60 seconds, then use count of minutes. Otherwise add one.
            long m = ( duration.getSeconds () % 60 == 0 ) ? countMinutes : ( countMinutes + 1 );
            result = ( m * Event.COST_PER_MINUTE );
        } else {
            System.out.println ( "ERROR - Reached impossible ELSE condition." );
        }
        return result;
    }

    @Override
    public int compareTo ( Event o ) {
        // Compare cost of each Event.
        // If cost is equal, then secondarily compare the id members so a '101' sorts before a '102.
        int c = this.getCost ().compareTo ( o.getCost () );
        if ( c == 0 ) {
            c = this.getId ().compareTo ( o.getId () );
        }
        return c;
    }

    @Override
    public String toString () {
        return "Event{ " + "id=" + id + " | durations=" + durations + " | cost=" + this.getCost () + " }";  // For debugging purposes.
    }

}

利用问题中给出的示例数据使用此类的示例。

List<Event> events = new ArrayList<> ( 4 );

List<Duration> d = new ArrayList<> ();
d.add ( Duration.parse ( "PT5M1S" ) );
events.add ( new Event ( 100 , d ) );

d = new ArrayList<> ();
d.add ( Duration.parse ( "PT1M7S" ) );
d.add ( Duration.parse ( "PT5M3S" ) );
events.add ( new Event ( 101 , d ) );

d = new ArrayList<> ();
d.add ( Duration.parse ( "PT7M11S" ) );
events.add ( new Event ( 102 , d ) );

d = new ArrayList<> ();
d.add ( Duration.parse ( "PT2M59S" ) );
d.add ( Duration.parse ( "PT4M38S" ) );
d.add ( Duration.parse ( "PT6M16S" ) );
events.add ( new Event ( 103 , d ) );

Collections.sort ( events );

System.out.println ( "events: \n" + events );

运行时。请注意,排序顺序现在是 100|102|101|103。

[事件{ id=100 |持续时间=[PT5M1S] |成本=480 },事件{ id=102 |持续时间=[PT7M11S] |成本=640 },事件{ id=101 |持续时间=[PT1M7S, PT5M3S] |成本=3830 },事件{ id=103 |持续时间=[PT2M59S, PT4M38S, PT6M16S] |成本=9910 }]

【讨论】:

  • 我已经修改了我当前的代码并发布了我在上面的帖子中遇到的一个问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 1970-01-01
  • 2018-09-09
  • 1970-01-01
  • 2015-01-19
  • 2017-06-25
  • 2020-05-26
相关资源
最近更新 更多