正确的类型
您使用了所有错误的数据类型。
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 }]