Java 查找两个数组之间的非公共元素

Java 查找两个数组之间的非公共元素,java,collections,set,Java,Collections,Set,在一次采访中,它被要求寻找两个字符串数组之间的非公共元素 Eg: String a[]={"a","b","c","d"}; String b[]={"b","c"}; O/p should be a,d 我已经回答了一个问题,即Java中的Set是使用哈希表实现的。带有Set的代码要简单得多: String[] a = {"a","b","c","d"}; String[] b = {"b", "c"}; Set<String> set = new HashSet<&

在一次采访中,它被要求寻找两个字符串数组之间的非公共元素

Eg: String a[]={"a","b","c","d"}; 
String b[]={"b","c"}; 
O/p should be a,d
我已经回答了一个问题,即Java中的Set是使用哈希表实现的。带有Set的代码要简单得多:

String[] a = {"a","b","c","d"};
String[] b = {"b", "c"};

Set<String> set = new HashSet<>(a.length);
for(String s : a){
    set.add(s);
}
for(String s : b){
    set.remove(s);
}
return set;
String[]a={“a”、“b”、“c”、“d”};
字符串[]b={“b”,“c”};
Set Set=新哈希集(a.长度);
for(字符串s:a){
设置。添加(s);
}
用于(字符串s:b){
设置。移除;
}
返回集;
现在我的问题是,还有其他更好的方法来实现这一点吗

String a[]={"a","b","c","d"}; 
String b[]={"b","c"}; 

List aLst = new ArrayList(Arrays.asList(a));
List bLst = new ArrayList(Arrays.asList(b));

aLst.removeAll(bLst);
System.out.println(aLst);

如果
[x,y],[x,z]
应该产生
[y,z]
以下是我的建议:

String[] a = {"a","b","c","d"};
String[] b = {"b", "c", "x"};

Set<String> set = new HashSet<>(Arrays.asList(a));
for (String s : new HashSet<>(Arrays.asList(b)) {
    if (!set.add(s))    // if it's already present
        set.remove(s);  // remove it from the result
}

您可以通过以下方式缩短代码

TreeSet set = new TreeSet(Arrays.asList(a));
set.removeAll(Arrays.asList(b));

我将分三个步骤处理此问题:

  • 查找
    a
    中的所有元素,但不查找
    b
  • 查找
    b
    中的所有元素,但不查找
    a
  • 把这两组加在一起
例如:

Set<String> aSet = new HashSet<>(Arrays.asList(a));
Set<String> bSet = new HashSet<>(Arrays.asList(b));

Set<String> aNotB = new HashSet<>(aSet);
aNotB.removeAll(bSet);

Set<String> bNotA = new HashSet<>(bSet);
bNotA.removeAll(aSet);

Set<String> onlyOne = new HashSet<>(aNotB);
onlyOne.addAll(bNotA);
setaset=newhashset(Arrays.asList(a));
Set bSet=newhashset(Arrays.asList(b));
Set aNotB=新哈希集(aSet);
aNotB.removeAll(bSet);
Set bNotA=新哈希集(bSet);
bNotA.removeAll(aSet);
Set onlyOne=新哈希集(aNotB);
仅限一人。addAll(bNotA);
(Java8中的流代码也很可能使这一点更简单…)


如果您不介意修改
aSet
bSet
,代码可以缩短,但我发现这个版本更容易阅读。

实际上,这扩展了Jon Skeet的答案,但使用Java 8的流

String[] result = Arrays.stream(a)
                        .filter((s) -> Arrays.stream(b).noneMatch(s::equals))
                        .toArray(String[]::new);

System.out.println(Arrays.toString(result));
守则的主要租户包括:

  • 过滤掉A中包含的任何元素,如果且仅当它不存在于B中时(通过短路终端操作符
    noneMatch
    ),检查该元素是否等于该流中的任何元素
  • 将结果收集到
    字符串[]
另一种方法是使用
设置
,然后再次使用流:

Set<String> setA = new HashSet<>(Arrays.asList(a));
Set<String> setB = new HashSet<>(Arrays.asList(b));

String[] setResult = setA.stream()
                         .filter((s) -> !setB.contains(s))
                         .toArray(String[]::new);
Set setA=newhashset(Arrays.asList(a));
Set setB=新的HashSet(Arrays.asList(b));
字符串[]setResult=setA.stream()
.filter((s)->!setB.contains)
.toArray(字符串[]::新建);


正如所指出的,非集合代码的主要问题是,在最坏的情况下,它是二次时间。这里的代码利用了对
集合#contains
的恒定访问时间,应该在大约线性时间内运行。

如果字符串仅为英文字母(或超过一个小字母表..甚至ASCII),我宁愿使用布尔[]通过char值而不是hashset等来提高性能。

使用这种方法,您将错过仅出现在
b
中的字符串,对吗?看起来输入已排序。。。这是偶然的,还是有保证的?@aioobe是偶然的,如果字符串未排序,请建议方法…./@aioobe是的,是偶然的,如果字符串未排序,请建议如何处理one@aioobe是的,非常多只包含a中的元素,但请告知如果数组未按1排序,那么在这种情况下我应该怎么做?如果我错了,请更正我,但是
删除
是多余的,对吗?设置不允许重复。不允许。它确保删除重复项。@aioobe集合中的add方法如果已经存在,则不会向集合中添加元素。你能详细说明一下搬家的必要性吗?阅读:如果一个元素没有被添加到集合中,为什么要删除它?@aioobe Downvote retracted!这个答案应该是可以接受的。
是,非常多只包含a
中的元素。我猜OP只对等式的一个方面感兴趣?@ChetanKinger:这是对OP当前代码的评论。我认为它没有回答书面问题。@SaurabhJhunjhunwala一个集合怎么会有重复?@KickButtowski,我说如果列表有重复项,它将不起作用。重复项有什么关系,@SaurabhJhunjhunwala?任务是找到非公共元素。此方法将非常有效。这取决于您是否将两个
.equal
元素视为两个不同的元素。但这种观点有点愚蠢。请注意,由于您对
a
的每个元素都迭代
b
,因此会产生二次复杂度。事实上,我不建议在这个用例中使用流。在我看来,这种算法以嵌套for循环的形式更具可读性。这是真实的,也是可悲的。让我想出一种利用集合的方法。你不需要通过
toList
。您可以直接在流上使用
toArray
。但是,您无法从
toArray
获取
字符串[]
。只能获取
对象[]
。尝试向下广播将导致
ClassCastException
。您可以使用另一个
toArray
方法:
。toArray(字符串[]::new)
Set<String> setA = new HashSet<>(Arrays.asList(a));
Set<String> setB = new HashSet<>(Arrays.asList(b));

String[] setResult = setA.stream()
                         .filter((s) -> !setB.contains(s))
                         .toArray(String[]::new);