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(