Java 比较树映射中的值
我在Java 比较树映射中的值,java,Java,我在Map中存储了一些日志,其中字符串表示操作,日期表示操作执行的日期 Sat Jan 11 06:00:00 IST 2014=Read User Fri May 15 05:45:56 IST 2015=Update User Tue Nov 21 07:23:00 IST 2017=Create User Tue Nov 21 08:34:00 IST 2017=Delete User Thu Nov 23 11:34:00 IST 2017=Create User
Map
中存储了一些日志,其中字符串表示操作,日期表示操作执行的日期
Sat Jan 11 06:00:00 IST 2014=Read User
Fri May 15 05:45:56 IST 2015=Update User
Tue Nov 21 07:23:00 IST 2017=Create User
Tue Nov 21 08:34:00 IST 2017=Delete User
Thu Nov 23 11:34:00 IST 2017=Create User
Mon Jul 30 10:34:20 IST 2018=Delete User
我的要求是,对于日志,创建一个新的映射,其中操作将是旧的操作+旧映射中位于其下方的相同值的操作
示例输出:
Sat Jan 11 06:00:00 IST 2014=Read User
Fri May 15 05:45:56 IST 2015=Update User
Tue Nov 21 07:23:00 IST 2017=Create User Create User [Thu Nov 23 11:34:00
IST 2017 ]
Tue Nov 21 08:34:00 IST 2017=Delete User Delete User [Mon Jul 30 10:34:20
IST 2018 ]
Thu Nov 23 11:34:00 IST 2017=Create User
Mon Jul 30 10:34:20 IST 2018=Delete User
我的解决方案:
Map<Date, String> auditMap = new TreeMap<Date, String>();
Map<Date, String> auditMap2 = new TreeMap<Date, String>();
Collection<String> ls = auditMap.values();
Object[] arr = ls.toArray();
int count = 1;
for(Map.Entry<Date, String> d: auditMap.entrySet()) {
String da = d.getValue();
for (int i = count ; i<arr.length ; i++) {
if(d.getValue().equals(arr[i])) {
da = da.concat(" ").concat((String) arr[i]).concat(" [" + auditMap.keySet().toArray()[i] +" ]");
}
}
count++;
auditMap2.put(d.getKey(), da);
}
for (Map.Entry<Date, String> d1: auditMap2.entrySet()) {
System.out.println(d1);
}
Map auditMap=newtreemap();
Map auditMap2=newtreemap();
集合ls=auditMap.values();
对象[]arr=ls.toArray();
整数计数=1;
对于(Map.Entry d:auditMap.entrySet()){
字符串da=d.getValue();
对于(int i=count;i则解决方案是将包含操作和数据的输入存储为列表作为成员。然后将其分组为操作
作为键,并使用groupingBy函数将时间
作为设定值。请参见以下算法是另一个带有O(n²)的版本
更具可读性的复杂性:
Map<Date, String> auditMap = new TreeMap<>();
Map<Date, String> result = new TreeMap<>();
List<Map.Entry<Date, String>> entries = Lists.newArrayList(auditMap.entrySet());
for (int i = 0; i < entries.size(); i++) {
Map.Entry<Date, String> entry = entries.get(i);
// This SB will contain all next occurrences
StringBuilder sb = new StringBuilder(entry.getValue());
// Checks all the next occurrences in the iterator for equal values
// To add them to the SB
for (int j = i + 1; j < entries.size(); j++) {
if (Objects.equals(entries.get(j).getValue(), entry.getValue())) {
sb.append(" ").append(entry.getValue());
sb.append(" [").append(entry.getKey()).append("]");
}
}
// Builds the result map
result.put(entry.getKey(), sb.toString());
}
Map auditMap=newtreemap();
映射结果=新树映射();
List entries=Lists.newArrayList(auditMap.entrySet());
对于(int i=0;i
复杂性分析:
原始地图上的循环统计n个项目
然后,嵌套循环计数(n-i+1)项,依次为:(n-1),(n-2),…,1项
总数是从1到n的总和,等于n*(n+1)/2。这意味着总复杂度是O(n²)
线性方法
可实现的最小复杂性为O(n)
,审计映射的大小为n
,因为您需要至少遍历每个审计操作一次
您的算法基本上是二次的(O(n^2)
)
如果需要更高的复杂性,则需要确保在auditMap
的每个元素上迭代一次:
Map<Date, String> auditMap = new TreeMap<Date, String>();
Map<String, AggregatedAction> aggregatedActions = new HashMap<>();
// Traverse each action once.
for (Map.Entry<Date, String> e : auditMap.entrySet()) {
Date date = e.getKey();
String action = e.getValue();
// If the number of types of actions is small, the lookup in the
// aggregatedActions map can be estimated to be O(1).
AggregatedAction aggregated = aggregatedActions.get(action);
if (aggregated == null) {
aggregated = new AggregatedAction(date, action);
aggregatedActions.put(action, aggregated);
} else {
aggregated.append(date);
}
}
// If you want a copy of your original map,
// otherwise you could just update it in place.
Map<Date, String> auditMap2 = new LinkedHashMap<Date, String>(auditMap);
// O(b) where b is the number of types of actions.
for (AggregatedAction action : aggregatedActions.values()) {
auditMap2.put(action.firstOccurence, action.concatenatedAction.toString());
}
复杂性分析
与
n
审核图的大小
b
aggregatedActions的大小
上述代码实现了O(n+b)=O(n)
ifb提高性能的步骤很少:
注意,我假设您需要就地解决方案
1) 根据值对树映射进行排序。它将帮助您停止迭代(稍后的步骤您将了解)。O(n logn)
2) 创建一个临时变量,用于存储开始/最后处理的元素
3) 开始迭代并检查每个值。在这种情况下,内部循环将在那里给出下一个值,如果外部循环值匹配,则将其添加到上一个输入值中。在每次迭代时,内部循环值将从迭代器中删除它,因此它将从树映射中删除,并将成为同一操作的值的一部分
4) 现在完成后,您的地图将具有所有值作为输出
请注意,具有两个循环(外部和内部)的迭代器将花费O(n)次。因此,最糟糕的解决方案是使用O(n log n)。在输出中,为什么有重复的“创建用户”和“删除相同”项。这是您要找的正确输出,还是您希望有特定操作(创建或删除等)的所有日期在同一个位置?输出是正确的。设想一下,我正在从地图上读取“创建用户”,然后我必须在下面查找其他“创建用户”。如果有,则添加两个操作。如果没有,则将原始值放入新地图中。请在计算下面和计算之后查看我的地图。是否要添加所有以下事件或JU不是第一个下一个吗?添加它下面的所有事件。但是没有测试它,请告诉我它是否有任何问题。while(iterator.hasNext())只需要对map中的第一个值进行一次迭代。它不会对其余的值进行迭代。但是,我喜欢你的想法。哦,这意味着foreachrestain
会消耗其余的值…哦,是的。当然。我当时更换了迭代器。这是怎么回事?看起来仍然是o(nlog(n)),我在考虑o(n)解决方案。我喜欢你的想法,但主要问题是上面的代码搜索事件并删除剩余的事件。请检查我的输出以获取参考,你的代码删除了最后两行。@amansaraf你确定吗?我想你保留了所有内容是因为复制:auditMap2=new TreeMap(auditMap)
。通过将auditMap
传递给TreeMap
的构造函数,它将auditMap
的所有元素复制到auditMap2
中。哎呀,我错过了这一点,我没有运行你的代码,只是通过查看它来分析输出。是的,它将复制所有内容以及操作,这看起来不错。非常好的操作方式实现。我唯一担心的是附加字符串的成本。如果成本太高,您可以用另一个结构(如果可能)来代替它,例如a(链接)列表。但我想你还是需要在某个时候把它合并成一个字符串。@amansaraf谢谢,从某种意义上说,这个问题是非常实际的,关于双迭代和更线性的方法的类似疑问可能很常见。关注“最优”这里的复杂性倾向于过早的优化,这弊大于利。这当然很有趣,但同时也带来了更多的冗长。一个结合了优化算法和优化算法的解决方案
public static final class AggregatedAction {
private final StringBuilder concatenatedAction = new StringBuilder();
private final String action;
private final Date firstOccurence;
public AggregatedAction(Date firstOccurence, String action) {
this.firstOccurence = firstOccurence;
this.action = action;
concatenatedAction.append(action);
}
public void append(Date nextOccurence) {
concatenatedAction.append(" ").append(action).append(" [").append(nextOccurence).append(" ]");
}
}