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

时间:2010-03-08 21:54:11

标签: java arraylist

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

第0条 - 姓名:John Smith;地区:N; ID:1
第1条 - 姓名:John Smith;地区:MW; ID:1
第2条 - 姓名:John Smith;地区:S; ID:1
第3条 - 姓名:Jane Doe;区域:NULL; ID:2
第4条 - 姓名:Jack Black;地区:N; ID:3
第6条 - 姓名:Jack Black;地区:MW; ID:3
第7条 - 姓名:Joe Don;地区:NE; ID:4

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

因此输出应如下所示: -

第0条 - 姓名:John Smith;区域:N,MW,S; ID:1
第1条 - 姓名:Jane Doe;区域:NULL; ID:2
第2条 - 姓名:Jack Black;地区:N,MW; ID:3
第3条 - 姓名:Joe Don;地区:NE; ID:4

您对解决此问题的最佳方法有何看法?我不是在寻找实际的代码,而是寻找最佳方法来完成它的想法或提示。

谢谢你的时间!!!

4 个答案:

答案 0 :(得分:2)

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

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

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());

答案 1 :(得分:2)

初始数据是否符合此格式?如果没有,您可能希望通过将所有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]

答案 2 :(得分:1)

这是一个完成你想要的伪代码。在抽象级别,您有一个Pair<K,V> (first, second)列表,按K排序,并且没有两对真正相等(即您可以拥有(k1,v1)(k1,v2),但是您列表中不能有两个(k1,v1)

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

List<Pair<K,V>> in;
List<Pair<K,List<V>>> out = [ ];

Pair<K,V> lastP = SENTINEL_PAIR; // lastP.first matches nothing
Pair<K,List<V>> lastGroup;

for (Pair<K,V> p : in) {
  if (p.first == lastP.first) {  // same group as last
    lastGroup.second.add(p.second);
  } else {                       // start a new group
    lastGroup = (p.first, [ p.second ]);
    out.add(lastGroup);
  }
  lastP = p;
}

在您的情况下,K是ID,V是区域。这是O(N)

答案 3 :(得分:0)

您是否看过谷歌的Multimap?它几乎是为这种类型的数据结构创建的,其中有一个键映射到Collection项。因此,在这种情况下,String名称将映射到CollectionRegion个对象。

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");