在Java中,从两个String Arrays返回公共元素的最有效方法是什么?我可以用一对for循环来做,但这似乎不是非常有效。根据我对similar SO question的评论,我能想出的最好的结果是转换为List
,然后应用retainAll
:
List<String> compareList = Arrays.asList(strArr1);
List<String> baseList = Arrays.asList(strArr2);
baseList.retainAll(compareList);
答案 0 :(得分:5)
这是一个单行:
compareList.retainAll(new HashSet<String>(baseList));
retainAll
impl(在AbstractCollection中)迭代this
,并在参数上使用contains()
。将参数转换为HashSet
将导致快速查找,因此retainAll
中的循环将尽快执行。
此外,名称baseList
暗示它是一个常量,因此如果缓存此值,您将获得显着的性能提升:
static final Set<String> BASE = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList("one", "two", "three", "etc")));
static void retainCommonWithBase(Collection<String> strings) {
strings.retainAll(BASE);
}
如果要保留原始列表,请执行以下操作:
static List<String> retainCommonWithBase(List<String> strings) {
List<String> result = new ArrayList<String>(strings);
result.retainAll(BASE);
return result;
}
答案 1 :(得分:3)
然后我会使用HashSets(和retainAll),这将使整个检查O(n)(对于第一组查找中的每个元素,如果它存在(contains()
),这是O (1)对于HashSet)。 List
的创建速度更快(HashSet
可能需要处理冲突......)。
请记住,Set
和List
具有不同的语义(列表允许重复元素,空值......)。
答案 2 :(得分:3)
对两个数组进行排序。
排序后,您可以使用两个索引对两个已排序的数组进行一次迭代。
这将是O(NlogN)。
答案 3 :(得分:1)
保留所有内容。改用set:
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] strings1={"a","b","b","c"},strings2={"b","c","c","d"};
List<String> list=Arrays.asList(strings1);
//list.retainAll(Arrays.asList(strings2)); // throws UnsupportedOperationException
//System.out.println(list);
Set<String> set=new LinkedHashSet<String>(Arrays.asList(strings1));
set.retainAll(Arrays.asList(strings2));
System.out.println(set);
}
}
答案 4 :(得分:1)
你想要的是交集。 看到: Intersection and union of ArrayLists in Java
使用基于哈希的集合提供了一个非常快的contains()方法,特别是对于具有优化哈希码的字符串。
如果您可以导入库,可以考虑使用Guava的Sets.intersection。
修改强>
不知道retainAll方法。
请注意,似乎未覆盖HashSets和LinkedHashSets的AbstractCollection实现是:
public boolean retainAll(Collection c){ boolean modified = false; Iterator it = iterator(); while(it.hasNext()){ if(!c.contains(it.next())){ it.remove(); modified = true; } } 返回修改; }
这意味着您在集合参数上调用contains()! 这意味着如果你传递一个List参数,那么对于每次迭代,你都会在列表的很多项上进行等于调用!
这就是为什么我不认为使用retainAll的上述实现是好的。
public <T> List<T> intersection(List<T> list1, List<T> list2) {
boolean firstIsBigger = list1.size() > list2.size();
List<T> big = firstIsBigger ? list1:list2;
Set<T> small = firstIsBigger ? new HashSet<T>(list2) : new HashSet<T>(list1);
return big.retainsAll(small)
}
选择将Set用作最小的列表,因为它可以更快地构建集合,并且一个大的列表很好地迭代...
请注意,原始列表参数之一可能会被修改,由您自行制作副本...
答案 5 :(得分:0)
我接受了采访,这个问题是他们在技术面试中问我的问题。我的回答是遵循以下代码:
public static void main(String[] args) {
String[] temp1 = {"a", "b", "c"};
String[] temp2 = {"c", "d", "a", "e", "f"};
String[] temp3 = {"b", "c", "a", "a", "f"};
ArrayList<String> list1 = new ArrayList<String>(Arrays.asList(temp1));
System.out.println("list1: " + list1);
ArrayList<String> list2 = new ArrayList<String>(Arrays.asList(temp2));
System.out.println("list2: " + list2);
ArrayList<String> list3 = new ArrayList<String>(Arrays.asList(temp3));
System.out.println("list3: " + list3);
list1.retainAll(list2);
list1.retainAll(list3);
for (String str : list1)
System.out.println("Commons: " + str);
}
输出:
list1: [a, b, c]
list2: [c, d, a, e, f]
list3: [b, c, a, a, f]
Commons: a
Commons: c