Java 从已排序的ArrayList中删除重复项,同时保留重复项中的某些元素

Java 从已排序的ArrayList中删除重复项,同时保留重复项中的某些元素,java,arraylist,Java,Arraylist,好的,一开始我觉得这很简单。但是我想不出一个有效的方法来解决这个问题。我想出了一个蛮力的方法来解决这个问题,但这不是很优雅。我有一个ArrayList。Contacts是一个具有多个成员(名称、区域、id)的VO类。ArrayList中存在重复项,因为不同的区域出现多次。列表按ID排序。下面是一个示例: 条目0-名称:John Smith;区域:N;ID:1 条目1——姓名:约翰·史密斯;地区:兆瓦;ID:1 条目2——姓名:约翰·史密斯;地区:S ;;ID:1 条目3——姓名:简·多伊;区域:

好的,一开始我觉得这很简单。但是我想不出一个有效的方法来解决这个问题。我想出了一个蛮力的方法来解决这个问题,但这不是很优雅。我有一个ArrayList。Contacts是一个具有多个成员(名称、区域、id)的VO类。ArrayList中存在重复项,因为不同的区域出现多次。列表按ID排序。下面是一个示例:

条目0-名称:John Smith;区域:N;ID:1
条目1——姓名:约翰·史密斯;地区:兆瓦;ID:1
条目2——姓名:约翰·史密斯;地区:S ;;ID:1
条目3——姓名:简·多伊;区域:空;ID:2
条目4——姓名:杰克·布莱克;区域:N;ID:3
条目6——姓名:杰克·布莱克;地区:兆瓦;ID:3
条目7——姓名:乔·登;区域:东北;身份证号码:4

我想通过将相同ID的重复区域组合在一起,将列表转换为下面的内容。因此,最终的列表应该只有4个不同的元素和组合的区域

因此,输出应如下所示:-

条目0-名称:John Smith;区域:N、MW、S;ID:1
条目1——姓名:简·多伊;区域:空;ID:2
条目2——姓名:杰克·布莱克;区域:N,MW;ID:3
条目3——姓名:乔·登;区域:东北;身份证号码:4

你对解决这个问题的最佳方法有什么想法?我不是在寻找实际的代码,而是寻找一些想法或技巧,以找到最好的方法来完成它


谢谢你的时间

这是一个伪代码,用于实现您想要的功能。在抽象层次上,您有一个按
K
排序的
对(第一,第二)
列表,并且没有两对是真正相等的(即,您可以有
(k1,v1)
(k1,v2)
,但列表中不能有两个
(k1,v1)

您希望将连续对
(k,v1)、(k,v2)、(k,v3)
合并到一个组
(k[v1,v2,v3])

中的列表;
列出=[];
Pair lastP=SENTINEL\u Pair;//lastP.first不匹配任何内容
配对组;
用于(对p:in){
如果(p.first==lastP.first){//与last相同的组
lastGroup.second.add(p.second);
}else{//启动一个新组
lastGroup=(p.first,[p.second]);
out.add(lastGroup);
}
lastP=p;
}

在您的例子中,
K
是ID,
V
是区域。这是
O(N)

您可以在将它们转储(并合并重复项)到树映射中时对它们进行迭代。然后从树映射值的排序视图中创建一个列表

在示例代码中,我假设您有一个带有id、name和regions字段的Entry类,最后一个是区域实例列表。可以很容易地将其更改为集合,将区域更改为字符串或您正在使用的任何内容。示例在将条目插入映射之前复制这些条目,因为它们在合并到其他条目时会被修改。

SortedMap<Integer, Entry> mergedEntriesMap = new TreeMap<Integer, Entry>();
for (Entry e : entries) {
  if (mergedEntriesMap.contains(e.id)) {
    Entry m = mergedEntriesMap.get(e);
    m.regions.addAll(e.regions);
  } else {
    Entry m = new Entry();
    // copy the entry to keep the original array clean
    m.id = e.id;
    m.name = e.name;
    m.regions = new ArrayList<Region>(e.regions);
    mergedEntriesMap.put(m.id, m);
  }
}

List<Entry> mergedEntries = new ArrayList<Entry>(mergedEntriesMap.values());
SortedMap mergedEntriesMap=newtreemap();
对于(条目e:条目){
if(mergedEntriesMap.contains(e.id)){
条目m=mergedEntriesMap.get(e);
m、 地区。添加所有(e.地区);
}否则{
条目m=新条目();
//复制条目以保持原始数组干净
m、 id=e.id;
m、 name=e.name;
m、 区域=新阵列列表(如区域);
mergedEntriesMap.put(m.id,m);
}
}
List mergedEntries=newarraylist(mergedEntriesMap.values());

初始数据是否采用这种格式?如果不是,您可能希望通过将所有ID分组在一起并形成逗号分隔的列表列来更改用于检索数据的查询。下面是sql中的一个示例

SELECT      Id, [Name], Regions = replace
            ((SELECT Region AS [data()]
            FROM RegionTable
            WHERE  Id = u.Id
            ORDER BY Region FOR xml path('')), ' ', ', ')
FROM        [User] u
WHERE       Id IS NOT NULL
GROUP BY Id, [Name]

你看过谷歌的吗?它基本上是为这种类型的数据结构创建的,其中有一个键映射到
集合
的项目。因此在这种情况下,
字符串
名称将映射到
区域
对象的
集合

Multimap<String, Region> names = HashMultimap.create();
for (Entry entry : entries) {
    names.put(entry.getName(), entry.getRegion());
}
// Now u can get the collection of regions by name
Collection<Region> johnsRegions = names.get("John Smith");
Multimap name=HashMultimap.create();
对于(条目:条目){
name.put(entry.getName(),entry.getRegion());
}
//现在,您可以按名称获取区域集合
集合johnregions=names.get(“John Smith”);

TreeMap
答案
containsKey
O(log N)
中。此解决方案是
O(N log N)
,因此不是最优的。最优是一个非常模糊的概念。OP可以只使用HashMap,但如果这是一个真正的大数据集,上面的代码是一个非常好的解决方案。一个优化是根本不使用contains()调用-只需调用get()并构造新的if get()返回null。在这里使用SortedMap并没有真正的帮助,但是-任何映射实现都可以工作。他希望对输出进行排序,如果输入也进行了排序,您可以通过迭代在O(N)中解决它,并且只希望在连续的条目中发生合并。我想他已经在处理O(N log N)在对输入列表进行预排序或对输出列表进行排序时,我的解决方案尝试同时解决合并和排序问题。这是一个非常好的解决方案。我使用HashMap而不是TreeMap和normal Map,而不是SortedMap。效果非常好。非常感谢!啊哈,我不知道可以在s中组合多行数据单行使用sql。不,数据不是以这种格式保存的。我可以修改sql。它与DB2相反。我熟悉REPLACE函数,但是,我不确定是否可以在DB2中以这种方式处理后序。数据不是XML格式,只是纯文本数据。谢谢!您可以使用jakarta commons multimap来完成此操作更优雅。看起来雅加达也有类似的。谢谢你的提示。
Multimap<String, Region> names = HashMultimap.create();
for (Entry entry : entries) {
    names.put(entry.getName(), entry.getRegion());
}
// Now u can get the collection of regions by name
Collection<Region> johnsRegions = names.get("John Smith");