Java:比较两个字符串数组并删除存在于两个数组中的元素

13
这主要是一道关于性能的问题。我有一个所有现有用户的主列表,存在于一个字符串数组 AllUids 中。我也有一个所有过期用户的列表,存在于一个字符串数组 EndUids 中。
我在 Java 中工作,我的目标是从主列表 AllUids 中删除任何存在于过期用户数组中的用户。我知道 PHP 有一个叫做 array_diff 的函数。
我想知道 Java 是否有任何可以比较两个数组并删除在两个数组中都相似的元素的方法。我的目标是性能,这就是为什么我问是否有内置函数。我不想添加任何特殊的包。
我考虑编写一个递归函数,但它似乎效率很低。这两个列表中都有成千上万的用户。为了存在于过期用户列表中,您必须存在于 AllUids 列表中,除非被删除。
示例:
String[] AllUids = {"Joe", "Tom", "Dan", "Bill", "Hector", "Ron"};

String[] EndUids = {"Dan", "Hector", "Ron"};

我所寻找的功能:

String[] ActiveUids = AllUids.RemoveSimilar(EndUids);

ActiveUids 会长成这样:

{"Joe", "Tom", "Bill"}

谢谢大家, 显然我能写出循环等代码,但我对其效率并不自信。这是每天在生产机器上运行的东西。

7个回答

13

Commons Collections有一个名为CollectionUtils的类和一个静态方法removeAll,该方法接受一个初始列表和一个要从该列表中移除的内容列表:

Collection removeAll(Collection collection,
                     Collection remove)

如果你使用用户列表而不是数组,那么这个代码应该能够满足你的需求。你可以使用Arrays.asList()将你的数组轻松转换为列表,所以...

Collection ActiveUids = CollectionUtils.removeAll(Arrays.asList(AllUids), 
                                                  Arrays.asList(EndUids))

编辑:我还在这方面进行了一些挖掘,并在Commons Collections中找到了以下使用ListUtils的解决方法:

List diff = ListUtils.subtract(Arrays.asList(AllUids), Arrays.asList(EndUids));

非常不错...


CollectionUtils对我没用,但如果我调用ActiveUids.removeall(EndUids),它就完美地工作了。最后我改变了存储字符串的方式。我使用以下代码创建了一个HashSet:HashSet <String>ActiveUids = new HashSet <String>(); 感谢大家的帮助。这正是我一直在寻找的! - user84786
它可以在Android上使用吗?:S - Ewoks

6

数组中的元素不能被“删除”。您可以将它们设置为null,但是数组的大小是固定的。

您可以使用java.util.SetremoveAll从一个集合中移除另一个集合,但我更喜欢使用Google Collections Library

Set<String> allUids = Sets.newHashSet("Joe", "Tom", "Dan",
                                      "Bill", "Hector", "Ron");
Set<String> endUids = Sets.newHashSet("Dan", "Hector", "Ron");
Set<String> activeUids = Sets.difference(allUids, endUids);

那感觉更加实用。

这种方法有点令人惊讶的是,Sets.difference 返回一个 视图。如果你真的想要 activeUids 成为一个“正常”的 Set(即:如果 allUidsendUids 发生变化,它的值不会改变,并且调用 size() 的时间复杂度为 O(1)),你应该立即将 Sets.difference 的结果传递给构造 Set 的某个东西。例如:Sets.newHashSet(Sets.difference(a, b)) - Laurence Gonsalves

4
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Bireswhar
 */
import java.util.Collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Repeated {

    public static void main(String[] args) {
//        Collection listOne = new ArrayList(Arrays.asList("milan","dingo", "elpha", "hafil", "meat", "iga", "neeta.peeta"));
//        Collection listTwo = new ArrayList(Arrays.asList("hafil", "iga", "binga", "mike", "dingo"));
//
//        listOne.retainAll( listTwo );
//        System.out.println( listOne );

        String[] s1 = {"ram", "raju", "seetha"};
        String[] s2 = {"ram"};
        List<String> s1List = new ArrayList(Arrays.asList(s1));
        for (String s : s2) {
            if (s1List.contains(s)) {
                s1List.remove(s);
            } else {
                s1List.add(s);
            }
             System.out.println("intersect on " + s1List);
        }
    }
}

3

最简单的解决方案可能是把所有元素放到Set中,然后使用removeAll。您可以像这样从数组转换为Set:

Set<String> activeUids = new HashSet<String>(Arrays.asList(activeUidsArray));

虽然您应该尽量避免使用数组,而是偏向于使用集合。


3
不要使用数组,应该使用Collection和removeAll()方法。至于性能:除非你做了一些愚蠢的事情导致O(n^2)运行时间,否则就忘记它吧。这是过早的优化,是无用/有害的类型。"成千上万的用户"并不算什么,除非你每秒钟都在进行数千次操作。
顺便说一下,PHP的"数组"实际上是哈希映射。

1
你可以把这些字符串放到一个集合中,然后使用removeAll方法。

0
    String s1 = "a,b,c,d";
    String s2 = "x,y,z,a,b,c";
    Set<String> set1 = new HashSet<String>();
    Set<String> set2 = new HashSet<String>();

    Set<String> set11 = new HashSet<String>();

    String[] splitS1 = s1.split(",");
    String[] splitS2 = s2.split(",");

    for(String s3:splitS1){
        set1.add(s3);
        set11.add(s3);
    }

    for(String s4:splitS2){
        set2.add(s4);
    }
    set1.removeAll(set2);
    set2.removeAll(set11);
    set1.addAll(set2);
    System.out.println(set1);

1
不鼓励只提供代码的答案。最好解释一下这段代码是如何解决问题的。 - abarisone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接