使用大集合或其中包含集合的等效映射是否很好?

时间:2019-01-04 12:09:30

标签: java data-structures

我从CompanyId标识的不同公司收集了一些数据点,每个数据点的name属性可能在一个公司或不同公司之间重复,问题是将所有数据点按其所属的name属性分组转移给不同的公司,这意味着如果其公司已存在于组中,我们将忽略数据点。

例如,数据点是:

companyId数据点名称
1 --------------------- A
1 --------------------- A
1 --------------------- B
2 --------------------- A
3 --------------------- B

结果将是:

数据点名称

A =================(1,A)(2,A)
B =================(1,B)(2,B)

我们可以看到公司1的第二个数据点A被忽略了。

据我所知,有两种方法可以进行重复数据删除工作。
1.构建Map<String(data point name), Set<Long(companyId)>>

Map<String, Set<Long>> dedup = new HashMap<>();
for(DataPoint dp : datapoints){
    String key = dp.getName();
    if(!dedup.contains(key)){
        dedup.put(key, new HashSet<Long>());
    }
    if(dedup.get(key).contains(dp.getCompanyId()){
        continue;
    }
    dedup.get(key).add(dp.getCompanyId());
}

2。建立庞大的Set<String>

Set<String> dedup;
for(DataPoint dp : datapoints){
    String key = dp.getName() + dp.getCompanyId();
    if(dedup.contains(key)){
        continue;
    }
    dedup.add(key);
}

那哪个更好或更合适?

2 个答案:

答案 0 :(得分:6)

方法(1)更好,因为方法2破坏了类型信息。

如果您想要一个经过测试的可靠实现并具有许多其他功能,则已经有适合这些情况的现成集合。

番石榴:https://google.github.io/guava/releases/21.0/api/docs/com/google/common/collect/HashMultimap.html

Eclipse集合: https://www.eclipse.org/collections/

如果您只想要一个简单的实现,则可以按照方法(1)自己完成。

结果将是这样的:

{
   "A": [1, 2],
   "B": [1, 2]
}

我不喜欢方法2的几个原因:

  1. 该方法不可靠。如果公司名称以数字结尾,则可能有重复数据删除错误。因此,您可能需要添加一个特殊字符,例如:<id>~<name>
  2. 如果以后需要再考虑一个参数,它将变得更加混乱。您可能需要做<id>~<name>~<pincode>等,
  3. 在方法1中,如果实现了仅基于companyId字段的哈希码和等于值,则可以直接将company bean直接放入

答案 1 :(得分:4)

最简单的方法(1)是:

Map<String, Set<Long>> dedup =
    datapoints.stream().collect(
        groupingBy(
            DataPoint::getName,
            mapping(DataPoint::getCompanyId, toSet()));

最简单的方法(2)是:

Set<String> dedup =
    datapoints.stream()
        .map(d -> d.getName() + d.getCompanyId())
        .collect(toSet());

您选择的内容取决于您要执行的操作,因为它们会产生不同类型的数据,并可能产生不同的结果。