优化 IndexedComparator性能,底层实现由array变为hashMap,避免循环equals

This commit is contained in:
mochouZero555 2024-07-22 10:26:47 +08:00
parent fb664be8c5
commit f8cd37acd9
2 changed files with 77 additions and 10 deletions

View File

@ -1,9 +1,10 @@
package cn.hutool.core.comparator; package cn.hutool.core.comparator;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
/** /**
* 按照数组的顺序正序排列数组的元素位置决定了对象的排序先后<br> * 按照数组的顺序正序排列数组的元素位置决定了对象的排序先后<br>
@ -16,7 +17,10 @@ import java.util.Comparator;
public class IndexedComparator<T> implements Comparator<T> { public class IndexedComparator<T> implements Comparator<T> {
private final boolean atEndIfMiss; private final boolean atEndIfMiss;
private final T[] array; /**
* map存储对象类型所在列表的位置,k为对象v为位置
*/
private final Map<? super T, Integer> map;
/** /**
* 构造 * 构造
@ -28,6 +32,19 @@ public class IndexedComparator<T> implements Comparator<T> {
this(false, objs); this(false, objs);
} }
/**
* 构造
*
* @param atEndIfMiss 如果不在列表中是否排在后边
* @param map 参与排序的mapmap中的value值大小决定了对象的排序先后
*/
@SuppressWarnings("unchecked")
private IndexedComparator(boolean atEndIfMiss, Map<? super T, Integer> map) {
this.atEndIfMiss = atEndIfMiss;
this.map = map;
}
/** /**
* 构造 * 构造
* *
@ -38,7 +55,10 @@ public class IndexedComparator<T> implements Comparator<T> {
public IndexedComparator(boolean atEndIfMiss, T... objs) { public IndexedComparator(boolean atEndIfMiss, T... objs) {
Assert.notNull(objs, "'objs' array must not be null"); Assert.notNull(objs, "'objs' array must not be null");
this.atEndIfMiss = atEndIfMiss; this.atEndIfMiss = atEndIfMiss;
this.array = objs; map = new HashMap<>(1 + (int) (objs.length / 0.75));
for (int i = 0; i < objs.length; i++) {
map.put(objs[i], i);
}
} }
@Override @Override
@ -47,8 +67,8 @@ public class IndexedComparator<T> implements Comparator<T> {
final int index2 = getOrder(o2); final int index2 = getOrder(o2);
if (index1 == index2) { if (index1 == index2) {
if (index1 < 0 || index1 == this.array.length) { if (index1 < 0 || index1 == this.map.size()) {
// 任意一个元素不在列表, 返回原顺序 // 任意一个元素不在map, 返回原顺序
return 1; return 1;
} }
@ -60,15 +80,15 @@ public class IndexedComparator<T> implements Comparator<T> {
} }
/** /**
* 查找对象类型所在列表的位置 * 查找对象类型所对应的顺序值,即在原列表中的顺序
* *
* @param object 对象 * @param object 对象
* @return 位置未找到位置根据{@link #atEndIfMiss}取不同值false返回-1否则返回列表长度 * @return 位置未找到位置根据{@link #atEndIfMiss}取不同值false返回-1否则返回map长度
*/ */
private int getOrder(T object) { private int getOrder(T object) {
int order = ArrayUtil.indexOf(array, object); Integer order = map.get(object);
if (order < 0) { if (order == null) {
order = this.atEndIfMiss ? this.array.length : -1; order = this.atEndIfMiss ? this.map.size() : -1;
} }
return order; return order;
} }

View File

@ -0,0 +1,47 @@
package cn.hutool.core.comparator;
import cn.hutool.core.collection.CollectionUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
public class IndexedComparatorTest {
@Test
public void sortTest() {
final Object[] arr ={"a", "b", new User("9", null), "1",3,null,"2"};
final Collection<Object> set = new HashSet<>(Arrays.asList(arr));
final List<Object> sortSet = CollectionUtil.sort(set, new IndexedComparator<>(arr));
Assert.assertEquals("a", sortSet.get(0));
Assert.assertEquals( new User("9", null), sortSet.get(2));
Assert.assertEquals(3, sortSet.get(4));
Assert.assertNull(sortSet.get(5));
}
@Test
public void reversedTest() {
final Object[] arr ={"a", "b", new User("9", null), "1",3,null,"2"};
final Collection<Object> set = new HashSet<>(Arrays.asList(arr));
final List<Object> sortSet = CollectionUtil.sort(set, new IndexedComparator<>(arr).reversed());
Assert.assertEquals("a", sortSet.get(6));
Assert.assertNull(sortSet.get(1));
Assert.assertEquals( new User("9", null), sortSet.get(4));
Assert.assertEquals(3, sortSet.get(2));
}
@Data
@AllArgsConstructor
static class User{
private String a;
private String b;
}
}