Java 数据集合并错误/随机?
我有一个Java 数据集合并错误/随机?,java,Java,我有一个.csv文件,看起来像这样: 123,1-1-2020,[Apple] 123,1-2-2020,[Apple] 123,1-2-2020,[Beer] 345,1-3-2020,[Bacon] 345,1-4-2020,[Cheese] 345,1-4-2020,[Sausage] 345,1-5-2020,[Bacon] 我制作了一个函数,用于查找任何行的编号和日期是否相似,行中的项目将在其旁边附加一个数字,以显示项目集中有多少项目: 123,1-1-2020,1,[Apple]
.csv
文件,看起来像这样:
123,1-1-2020,[Apple]
123,1-2-2020,[Apple]
123,1-2-2020,[Beer]
345,1-3-2020,[Bacon]
345,1-4-2020,[Cheese]
345,1-4-2020,[Sausage]
345,1-5-2020,[Bacon]
我制作了一个函数,用于查找任何行的编号
和日期
是否相似,行中的项目将在其旁边附加一个数字,以显示项目集中有多少项目:
123,1-1-2020,1,[Apple]
123,1-2-2020,2,[Apple, Beer]
345,1-3-2020,1,[Bacon]
345,1-4-2020,2,[Cheese,Sausage]
345,1-5-2020,1,[Bacon]
虽然这是预期的结果,实际结果是使用我的算法得到的一组更大的数据,但项目有时会随机不计数并丢失(整行消失)。上述示例有时会变成:
123,1-1-2020,1,[Apple]
123,1-2-2020,2,[Apple, Beer]
345,1-3-2020,1,[Bacon]
345,1-4-2020,2,[Cheese,Sausage]
345,1-5-2020,1,[Bacon]
// Any one of those output lines would sometimes disappear entirely.
我很困惑为什么会这样。下面是我实现的算法:
protected List<Receipt> convert(List<Receipt> list) {
List<Receipt> receipts = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
List<Receipt> temp = new ArrayList<>();
temp.add(list.get(i));
for (int j = i + 1; j < list.size(); j++) {
if (list.get(i).getNumber().equals(list.get(j).getNumber())) {
temp.add(list.get(j));
}
}
Map<String, Set<String>> map = new HashMap<>();
for (Receipt r : temp) {
if (!map.containsKey(r.getDate())) {
map.put(r.getDate(), r.getItems());
} else {
map.replace(r.getDate(), merge(map.get(r.getDate()), r.getItems()));
}
}
for (Map.Entry<String, Set<String>> m : map.entrySet()) {
receipts.add(new Receipt(list.get(i).getNumber(), m.getKey(), m.getValue()));
}
i = i + temp.size();
}
return receipts;
}
// Merge function used above to append two item sets.
private static Set<String> merge(Set<String> a, Set<String> b) {
return new HashSet<>() {
{
addAll(a);
addAll(b);
}
};
}
受保护列表转换(列表){
列表收据=新的ArrayList();
对于(int i=0;i
其中,.csv
中的每一行都被制作成一个收据
对象,该对象具有(字符串)
getNumber()
,(字符串)
getDate()
和(设置)
getItems()
方法
例如,对于具有类似格式且有数十万行的.csv,在原始数据集中,Bacon
项被查找了1334次,但我的算法的输出,Bacon
仅在1160-1240次之间随机出现。所有其他项目也会出现这种情况。还有一些奇怪的行为,一些随机的行也错误地附加了项目(相同的数字,不同的日期,但仍然附加)
这种随机性的原因可能是什么
编辑:正如评论部分提到的建议,原因似乎是
i++
和i=i+temp.size()
错误地增加了i
值。首先,在merge()
方法中使用了双括号语法,这是非常不鼓励的。例如,参见以下答案:
其次,您的代码对列表的迭代次数太多,您可以(也应该)在一次迭代中完成
在继续之前,我们需要查看Receipt
类,该类未在问题中显示,但我们可以推断它看起来如下所示:
123,1-1-2020,[Apple]
123,1-2-2020,[Apple]
123,1-2-2020,[Beer]
345,1-3-2020,[Bacon]
345,1-4-2020,[Cheese]
345,1-4-2020,[Sausage]
345,1-5-2020,[Bacon]
公共类收据{
私有最终字符串编号;
私人最终字符串日期;
私人最终设置项目;
公共收据(字符串编号、字符串日期、设置项目){
这个数字=数字;
this.date=日期;
这个项目=项目;
}
公共字符串getNumber(){
返回此.number;
}
公共字符串getDate(){
返回此日期;
}
公共集合getItems(){
归还此物品;
}
}
目标是合并共享编号
和日期
的收据。要在一次迭代中实现这一点,我们需要一个映射
,由数字
和日期
组合键控。有三种方法可以做到这一点:
equals()
和hashCode()
仅基于这两个字段,忽略项
字段。这是最简单的解决方案,但需要修改Receipt
类,并定义“相等”以不包括项目列表,这是一个有争议的决定,因此我们不要这样做
equals()
和hashCode()
。这样做的优点是只保留收据
,但确实需要一个新类
Receipt
类作为键,但提供仅比较两个字段的Map
类自定义比较器。使用Java8,我们可以在不创建新类的情况下实现这一点,所以让我们试试。我们需要使用TreeMap
来提供定制的比较器
TreeMap
,使用一个自定义的比较器
,迭代列表一次,在执行过程中合并项目,最后迭代映射以构建合并收据的新列表
受保护的静态列表转换(列表){
Map Map=newtreemap(Comparator.comparing(receive::getDate)
.然后比较(收据::getNumber));
用于(收据:列表){
map.merge(receipt,receipt.getItems(),(v1,v2)->{
设置新闻集=新树集(v1);
新闻集addAll(v2);
返回新闻集;
});
}
列表结果=新建ArrayList();
for(条目:map.entrySet()){
结果.添加(新收据(entry.getKey().getNumber(),
entry.getKey().getDate(),
entry.getValue());
}
返回结果;
}
当然,也可以使用流逻辑完成:
受保护的静态列表转换(列表){
return list.stream()
.collect(收集器.groupingBy(