【问题标题】:ArrayList duplicates removal [duplicate]ArrayList 重复删除 [重复]
【发布时间】:2016-07-08 15:01:42
【问题描述】:

我有一个带有 ping 的 Arraylist,这些是与名称相关联的日期,我想删除所有重复的名称并保留最接近的名称日期。

代码

private ArrayList <String> deleteDuplicates() {
  ArrayList <Ping> tempPings = new ArrayList < Ping > ();
  tempPings.addAll(jaws.pastMonth());
  for (int i = 0; i < tempPings.size(); i++) {
    Ping tempPing = tempPings.get(i);
    for (int j = i + 1; j < tempPings.size() - 1; j++) {
      Ping tempPing2 = tempPings.get(j);
      if (tempPing.getName().equals(tempPing2.getName())) {
        if (changePingToDate(tempPing2).before(changePingToDate(tempPing))) {
          tempPings.remove(j);
        }
      }
    }
  }
  return pingToNames(tempPings);
}

changePingToDate() 是将日期字符串转换为公历的方法。

当我使用此代码时,它会删除大部分重复项,但每次循环时仍有一些剩余部分。我也试过了,没有比较日期,仍然是同样的问题。有人可以帮忙吗?

感谢您的帮助!

【问题讨论】:

  • @aribeiro 嗨,我已经检查了这个答案,但它对我的问题没有帮助,我的 .equals 似乎工作正常,名称完全相同,例如“Mary Lee”多次和它似乎在挑选要删除的内容。
  • 您正在调用.remove(),它会在您遍历列表时修改列表的大小和您正在查看的索引。您正在跳过值。
  • 使用迭代器。我不想仅仅为了它而在这里添加另一个答案。 SO 和 Google 上都有大量可用资源。
  • @cricket_007 好的,谢谢,我不完全确定我是否理解,如果它在我比较它之后删除值,为什么会改变我正在查看的索引?您对如何解决此问题有任何想法吗?谢谢。
  • 或将所有值转储到Set 以删除重复项。

标签: java date arraylist duplicates


【解决方案1】:
ArrayList<String> values = new ArrayLiist<>(Arrays.asList(
        "apple",
        "banana",
        "grape",
        "banana",
        "apple",
        "banana",
        "apple",
        "grape"
));

使用 Java 8?

values = values.stream().distinct().collect(Collectors.toCollection(ArrayList::new));

只有 Java 7?

values = new ArrayList<>(new LinkedHashSet<>(values));

两者的输出都是

[apple, banana, grape]

然后像往常一样遍历列表来进行日期操作。

【讨论】:

  • 这将非常有帮助,不幸的是,我们仍然需要比较日期并为每个 ping 留下唯一的名称以及最接近的时间。不过谢谢,以后可以看到这非常方便!
  • 删除重复项后循环遍历列表。
  • @cricket_007 与 LinkedHashSet 的第二种方式相比,流的优势是什么?
  • 我想说流的内存效率更高。 HashSet 创建 2 个中间数据集合
【解决方案2】:

在列表中循环时不要从列表中删除元素。因此,将您要删除的所有项目添加到另一个列表中,最后从 tempPings 中删除所有项目。

private ArrayList <String> deleteDuplicates() {
  ArrayList <Ping> tempPings = new ArrayList < Ping > ();
  tempPings.addAll(jaws.pastMonth());

  ArrayList <Ping> pingsToRemove = new ArrayList <Ping> ();
  for (int i = 0; i < tempPings.size(); i++) {
    Ping tempPing = tempPings.get(i);
    for (int j = i + 1; j < tempPings.size() - 1; j++) {
      Ping tempPing2 = tempPings.get(j);
      if (tempPing.getName().equals(tempPing2.getName())) {
        if (changePingToDate(tempPing2).before(changePingToDate(tempPing))) {

            pingsToRemove.add(tempPings.get(j));

        }
      }
    }
  }

  tempPings.removeAll(pingsToRemove);
  return pingToNames(tempPings);
}

【讨论】:

  • 你可以使用Iterator.remove
  • 我已经尝试过这种方式,但最终在我的 400 个奇数大小的数组中,要删除 9060 个元素,完全不知道为什么会发生这种情况,如果我要使用迭代器会那需要使用两个?而且我从未见过并使用迭代器来迭代已检查的元素(在 for j = i + 1 的情况下)的实现,这可能吗?谢谢。
  • 尝试在pingsToRemove.add(tempPings.get(j));之前添加if语句来检查tempPings.get(j)是否已经添加。喜欢if(!pingsToRemove.contains(tempPings.get(j)))
  • 这仍然包含由for (int j = i + 1; j &lt; tempPings.size() - 1; j++) {引起的off-by-one问题。如果您的列表大小为 10,则您的内部循环将循环,而 j &lt; 9,您将永远将任何项目与 j = 9 项目进行比较。你的第一个循环可以写成for (int i = 0; i &lt; tempPings.size() - 1; i++) {- 1 在那里是可以的,因为你在j = i + 1 开始你的第二个循环,但是在第二个循环的循环条件下它是不可以的。
【解决方案3】:

由于您无法理解为什么您正在执行的 remove() 操作会导致问题。我会尽力解释。

这是一个概括性的解释,旨在让您了解代码中的问题。

我有一桶 10 样东西。在每次迭代中,我都会检查以确保我检查到bucket.size()。如果我删除i 的项目,i+1 的项目将取代它。删除过程确保 bucket.size() 现在等于 9,而不是 10。循环将我的 i 递增 1。跳过位于 i+1 和现在位于 i 的元素。

【讨论】:

  • 这样更有意义,非常感谢!
  • @B.KLewis This postthis post 展示了使用迭代器来做这件事的非常干净的方法。
猜你喜欢
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-24
  • 2014-03-25
  • 2015-12-12
  • 2017-08-02
  • 1970-01-01
相关资源
最近更新 更多