【问题标题】:How do I add non-existing values in from arrayList2 to arrayList1?如何将不存在的值从 arrayList2 添加到 arrayList1?
【发布时间】:2015-08-09 12:21:44
【问题描述】:

假设我有一个点的arrayList1。数据结构是这样的:

(1,2)->(2,2)->(3,2)->(4,2)->(5,2)

我还有另一个 arrayList2 点:

(2,2)->(1,2)->(8,5)->(9,3)

如何比较两个列表并将 arrayList2 中不存在的值添加到 arrayList1?

当前解决方案

我现在能想到的唯一方法是使用 for 循环来比较 arrayList1 中的每个点,例如,if(!arrayList1.contains(arrayList2.get(i))){ arrayList1.add(arrayList2.get(i)); } i++;

是否有更有效的方法或已经从类中准备好的方法?因为我有 arrayList1 直到 arrayList6 来比较和替换....

【问题讨论】:

标签: java arraylist set array-merge no-duplicates


【解决方案1】:
  1. 单线爱好者 (running demo):

    List<Point> list3 = new ArrayList<Point>(new HashSet<Point>(list1){{ addAll(list2); }});
    
  2. 安全版 * (running demo):

    Set<String> tmpSet = new HashSet<String>(arrayList1);
    tmpSet.addAll(arrayList2);
    List<String> mergedList = new ArrayList<String>(tmpSet);
    

    * 正如 Bruce Wayne 正确指出的那样,Double Brace initialization(单行示例,也用于两个示例中以填充前两个列表)应谨慎使用,因为以下文章中描述了潜在的缺点:

    Don’t be “Clever”: The Double Curly Braces Anti Pattern

说明Sets 不能包含重复项,所以使用一个作为过渡向量。

示例 1 代码:

List<String> arrayList1 = new ArrayList<String>(){{ add("One"); add("Two");   }};
List<String> arrayList2 = new ArrayList<String>(){{ add("Two"); add("Three"); }};   
List<String> mergedList = new ArrayList<String>(new HashSet<String>(arrayList1){{ addAll(arrayList2); }});
System.out.println(mergedList);

输出:[一、二、三]

示例2代码:

List<String> arrayList1 = new ArrayList<String>(){{ add("One"); add("Two");   }}; 
List<String> arrayList2 = new ArrayList<String>(){{ add("Two"); add("Three"); }}; 
Set<String> tmpSet = new HashSet<String>(arrayList1);
tmpSet.addAll(arrayList2);
List<String> mergedList = new ArrayList<String>(tmpSet);
System.out.println(mergedList);

输出:[一、二、三]

【讨论】:

  • 这太酷了!假设我有arrayList3,我也可以一行完成吗?喜欢List&lt;String&gt; mergedList = new ArrayList&lt;String&gt;(new HashSet&lt;String&gt;(arrayList1){{ addAll(arrayList2); addAll(arrayList3); }});
  • 对不起,我很兴奋,直到我忘了尝试大声笑。谢谢!这节省了我的很多代码行!
  • @Mark,您的兴奋是有道理的,但请理解您正在创建太多匿名内部类以换取语法糖。在您决定双括号初始化确实是您想要的之前,请阅读 this 博客文章。此外,可读性几乎总是胜过节省代码行数,我不确定使用这种模式是否最适合您。
  • 同意@Mark,有了您更新的答案,OP 肯定更有能力做出明智的决定。感谢您抽出宝贵时间采纳我的建议。
【解决方案2】:

如果时间复杂度是您的首要任务,请将List1 中的所有点添加到HashSet&lt;Point&gt;

然后,对于之后的每个列表,循环遍历它并查看该集合是否包含每个点,如果不包含,则将其添加到 List1

Set<Point> pointsInList1 = new HashSet<>(list1);
for(Point p : list2)
{
    if(!pointsInList1.contains(p)) {
        list1.add(p);
        pointsInList1.add(p);
    }
}

//Repeat for other lists

这个解与最大列表的大小成线性关系。

【讨论】:

  • 这不是和我目前的解决方案一样或者稍微简单一点吗?只是你正在使用HashSetforeach 循环?你基本上是在遍历每个列表,比较每个节点,如果它不存在就添加它,对吧?
  • @Mark,您的解决方案的时间复杂度(从我可以从 sn-p 推断出的)是二次或 O(mxn) 其中 m i> 和 n 是两个列表的大小。通过使用HashSet,您正在用时间复杂度换取空间,并且检查Point 是否存在于list1 中现在是一个O(1) 操作。因此总体时间复杂度是线性
【解决方案3】:

它可以有多种解决方案。当您使用 java.awt.Point 类时,该类已经覆盖了 equals 方法(基于坐标)。 因此,您可以轻松使用List 类的contains 方法。

for(Point point : list2){
     if(!list1.contains(point)){
         list1.add(point);
     }
}

确保使用for each 循环以获得更好的性能(不要使用基于索引的循环(如果您使用LinkedList,则会有所不同)。

ii) 另一种选择是使用java.util.Set 并使用其方法addAll(Set)。由于 Set 不会全部重复,因此会有效地合并元素。

【讨论】:

  • for each 循环如何获得更好、更显着的性能?基本上,算法与我当前的解决方案相同,对吧?将list2中的每个节点与list1进行比较,如果list1中不存在,则将其添加到list1中,对吧?
  • 它与arrayList没有任何区别,因为它是索引的。因此,get(i) 需要 O(1)。但是在linkedList get(i) 是O(i) 操作,因为它必须遍历。因此,如果您使用基于索引的循环,则每次调用 get(i) 时,它都会从 0 开始并进行扫描,但在 for each 的情况下 - 它使用一个迭代器,该迭代器包含对当前元素的引用,而不是从 0 开始。是您正在做同样的事情,但是当我回复时,此代码不存在。否则你可以使用 Set。
【解决方案4】:

您应该使用Set。这是一个没有重复的集合。所以你可以添加两次相同的值,它只会出现一次。

这意味着您可以在您的Set 中添加多个List,其中不会有重复项。

    Set setA = new HashSet(); 

    ArrayList<Point> points1 = new ArrayList<Point>();
    ArrayList<Point> points2 = new ArrayList<Point>();

    Point element1 = new Point(0,0);
    Point element2 = new Point(0,1);
    Point element3 = new Point(0,0);
    Point element4 = new Point(0,2);

    points1.add(element1); 
    points1.add(element2); 
    points1.add(element3);

    points2.add(element1);
    points2.add(element4);

    setA.addAll(points1);
    setA.addAll(points2);

    Iterator<Point> it = setA.iterator();
    while(it.hasNext())
        System.out.println(it.next());

输出:

java.awt.Point[x=0,y=0]
java.awt.Point[x=0,y=1]
java.awt.Point[x=0,y=2]

【讨论】:

  • 我只是将它添加到我的评论中。
【解决方案5】:

你可以这样做

    list2.removeAll(list1);
    list1.addAll(list2);

【讨论】:

  • 这将修改所有其他列表,我不确定 OP 是否需要。
【解决方案6】:

你必须在你的 Point Class 中覆盖你的 equal 函数

然后您可以遍历这两个列表,并比较它们的值。

【讨论】:

    【解决方案7】:

    如何比较两个列表

    这很简单,只需使用 equals 即可。

    将 arrayList2 中不存在的值添加到 arrayList1

    • 从arrayList2 中删除arrayList1 的所有元素并将其添加到arrayList2。这样只会将新元素添加到 arrayList2
    • 获取差异(arrayList1 - arrayList2)并将它们添加到arrayList2(例如CollectionUtils

    您当前的解决方案可能是错误的(它会跳过一个元素或永远运行,具体取决于您的循环):

    if(arrayList1.contains(arrayList2.get(i))) {
      i++; // this shouldn't be there if done in the loop
    } else {
      arrayList1.add(arrayList2.get(i)); // here a ++ is needed if not in the loop
    }
    

    有没有更有效的方法

    一个小建议:
    首先,让它工作(并具有良好的 UnitTest 覆盖率)。然后(只有那时!)如果需要优化!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-09
      • 1970-01-01
      • 1970-01-01
      • 2019-08-21
      • 1970-01-01
      • 2018-05-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多