此代码需要9分钟才能运行一组5,600个对象:
public Set<UnDirectedPair<T>> getAllUndirectedPairs(Set<T> setObjects) {
Set<T> setObjectsProcessed = new TreeSet();
Set<UnDirectedPair<T>> setPairs;
setPairs = new TreeSet();
Iterator<T> setObjectsIteratorA = setObjects.iterator();
Iterator<T> setObjectsIteratorB;
T currTA;
T currTB;
while (setObjectsIteratorA.hasNext()) {
currTA = setObjectsIteratorA.next();
setObjectsProcessed.add(currTA);
setObjectsIteratorB = setObjects.iterator();
while (setObjectsIteratorB.hasNext()) {
currTB = setObjectsIteratorB.next();
if (!setObjectsProcessed.contains(currTB) && !currTA.equals(currTB)) {
setPairs.add(new UnDirectedPair(currTA, currTB));
}
}
setObjectsProcessed.add(currTA);
}
return setPairs;
}
寻找一种大幅减少运行时间的方法......想法?
[背景技术] 该集包含人物。集合中有重复项(相同的人,但由于输入时的错误,属性略有不同)。我有方法需要2人并进行必要的更正。因此,作为一个初步步骤,我需要创建一组(人,人)对,这些对将被用于这些方法。
答案 0 :(得分:1)
我建议的一个技巧是保持外循环和内循环的反击。
int outerCount=0;
while (setObjectsIteratorA.hasNext()) {
currTA = setObjectsIteratorA.next();
setObjectsProcessed.add(currTA);
setObjectsIteratorB = setObjects.iterator();
int innerCount=0;
while (setObjectsIteratorB.hasNext()) {
currTB = setObjectsIteratorB.next();
if (innerCount++>outerCount && !currTA.equals(currTB)) {
setPairs.add(new UnDirectedPair(currTA, currTB));
}
}
outerCount++;
setObjectsProcessed.add(currTA);
}
return setPairs;
这将保存最后一个包含的logN操作。
背后的逻辑是:由于两个Iterator在同一个集合上,而ObjectProcessedSet的唯一目的是维护已处理Object的记录,你可以实现与那个索引相比较。
实施例
Set1={1,1,2,4,5}
Iterator1 iteratorOuter=Set1.Iterator();
int outerCount=0;
while(iteratorOuter.hasNext()){
Iterator2 iteratorInner=Set1.Iterator();
int currA=iteratorOuter.next();
while(iteratorInner.hasNext()){
int CurrB=iteratorInner.next();
//Now here if CurraA=4 and CurrB=2 it is obvious it has been processed
//If currB =5 it is obviously has not been processed.
}
}
答案 1 :(得分:0)
一个应该给你一个非常好的加速的解决方案是首先对集合进行排序,然后仅比较集合中的相邻条目。
当然,这意味着您需要为每个Person
设置一个类似的密钥(例如,它的名称),并且所有重复密钥的密钥必须相同。
然后你的代码看起来像这样:
SortedSet<Person> persons = new TreeSet<>(...);
Person last = null;
for (Person current : persons) {
if (last != null) {
setPairs.add(new UnDirectedPair(last, current));
}
last = current;
}
如果Person
未实现Comparable
(或通过错误字段进行比较),则可以在创建Comparator
时指定TreeSet
。
此解决方案在O(n * log n)中运行,之后只有O(n)对才能运行。只有5600人,这应该非常快。
在这种情况下,您还可以使setPairs
成为List
以获得更多性能(尽管很少)。或者你根本不创建对的集合,只需调用你的方法直接在循环中纠正Person
个对象。
答案 2 :(得分:0)
感谢您提出好的建议。
基本的损伤是我的班级UnDirectedPair
,它有昂贵的equals
和compareTo
方法。我用一个剥离的裸Pair类替换它。
这使得代码可以在大约10秒内运行。
尽管如此,使用套装操作似乎代价高昂。随着@mawia建议修改了一下,设置可以完全不在图片之外。最终代码在 2秒内而不是9月40日运行 - 返回19,471,920对对象列表!!
public List<Pair<T>> getAllUndirectedPairsAsList(Set<T> setObjects) {
List<T> listObjects = new ArrayList();
listObjects.addAll(setObjects);
List<Pair<T>> listPairs = new ArrayList();
Iterator<T> listIterator1 = listObjects.listIterator();
Iterator<T> listIterator2;
int count = 1;
T object1;
while (listIterator1.hasNext()) {
object1 = listIterator1.next();
listIterator2 = listObjects.listIterator(count++);
while (listIterator2.hasNext()) {
listPairs.add(new Pair(object1, listIterator2.next()));
}
}
return listPairs;
}