[Enhancement] Improve list comparing performance (#4880)
The function equalSets is not efficient enough currently, the time complexity is O(n^2). To improve the performance of comparing two lists, this patch tries to use hash map structure to make the time complexity to be O(n).
This commit is contained in:
@ -50,6 +50,7 @@ import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Root of the expr node hierarchy.
|
||||
@ -482,13 +483,40 @@ abstract public class Expr extends TreeNode<Expr> implements ParseNode, Cloneabl
|
||||
|
||||
/**
|
||||
* Return true if l1 equals l2 when both lists are interpreted as sets.
|
||||
* TODO: come up with something better than O(n^2)?
|
||||
*/
|
||||
public static <C extends Expr> boolean equalSets(List<C> l1, List<C> l2) {
|
||||
if (l1.size() != l2.size()) {
|
||||
return false;
|
||||
}
|
||||
return l1.containsAll(l2) && l2.containsAll(l1);
|
||||
Map cMap1 = toCountMap(l1);
|
||||
Map cMap2 = toCountMap(l2);
|
||||
if (cMap1.size() != cMap2.size()) {
|
||||
return false;
|
||||
}
|
||||
Iterator it = cMap1.keySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
C obj = (C) it.next();
|
||||
Integer count1 = (Integer) cMap1.get(obj);
|
||||
Integer count2 = (Integer) cMap2.get(obj);
|
||||
if (count2 == null || count1 != count2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static <C extends Expr> HashMap<C, Integer> toCountMap(List<C> list) {
|
||||
HashMap countMap = new HashMap<C,Integer>();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
C obj = list.get(i);
|
||||
Integer count = (Integer) countMap.get(obj);
|
||||
if (count == null) {
|
||||
countMap.put(obj, 1);
|
||||
} else {
|
||||
countMap.put(obj, count+1);
|
||||
}
|
||||
}
|
||||
return countMap;
|
||||
}
|
||||
|
||||
public void analyzeNoThrow(Analyzer analyzer) {
|
||||
|
||||
@ -29,6 +29,8 @@ import org.junit.Test;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import mockit.Expectations;
|
||||
import mockit.Injectable;
|
||||
@ -159,4 +161,27 @@ public class ExprTest {
|
||||
StringLiteral castStringLiteral2 = (StringLiteral) stringLiteral.uncheckedCastTo(Type.VARCHAR);
|
||||
Assert.assertTrue(stringLiteral == castStringLiteral2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualSets() {
|
||||
Expr r1 = new DateLiteral(2020, 10, 20);
|
||||
Expr r2 = new DateLiteral(2020, 10, 21);
|
||||
Expr r3 = new DateLiteral(2020, 10, 22);
|
||||
Expr r4 = new DateLiteral(2020, 10, 23);
|
||||
|
||||
//list1 equal list2
|
||||
List<Expr> list1 = new ArrayList<>();
|
||||
List<Expr> list2 = new ArrayList<>();
|
||||
list1.add(r1);
|
||||
list1.add(r2);
|
||||
list1.add(r3);
|
||||
list2.add(r1);
|
||||
list2.add(r2);
|
||||
list2.add(r3);
|
||||
Assert.assertTrue(Expr.equalSets(list1, list2));
|
||||
|
||||
//list3 not equal list4
|
||||
list2.add(r4);
|
||||
Assert.assertFalse(Expr.equalSets(list1, list2));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user