说明
在实际编程中,经常会遇到数组或列表去掉重复项,以保持成员唯一性。各个语言的实现方式均不尽相同。针对数组去重,Java实现方式有多种,比如新建数组来存储非重复项,或者在原有基础上删除掉重复的项,也可以利用数据结构Set或ArrayList来达到去重复。以下18种方式都可以实现,但每一种方法都不尽相同,有的很简单,几行代码搞定,有的则稍复杂,需要10来行代码。通过对比不同的实现,我们可以从中发现Java语言里一些不同的东西。
方式
//1. 双循环遍历全部成员,将当前项目与左边项逐个进行对比,如果值相同且下标相同表示唯一,其他则认为是重复项进行忽略。 | |
static int[] unique(int arr[]) { | |
int newArr[] = new int[arr.length]; | |
int x =; | |
for (int i =, l = arr.length; i < l; i++) { | |
for (int j =; j <= i; j++) { | |
if (arr[i] == arr[j]) { | |
if (i == j) { | |
newArr[x] = arr[i]; | |
x++; | |
} | |
break ; | |
} | |
} | |
} | |
int result[] = Arrays.copyOf(newArr, x); | |
return result; | |
} | |
//2. 先将数组转换为List,利用List的indexOf方法查找下标,当下标匹配时表示唯一,添加到新列表中 | |
static Integer [] unique2(Integer arr[]) { | |
int x =; | |
List<Integer> list = new ArrayList<>(Arrays.asList(arr)); | |
int l = list.size(); | |
for (int i =; i < l; i++) { | |
if (list.indexOf(arr[i]) == i) { | |
list.add(arr[i]); | |
x++; | |
} | |
} | |
// 返回取出的非重复项 | |
Integer[] result = new Integer[x]; | |
return list.subList(list.size() - x, list.size()).toArray(result); | |
} | |
//3. 在原有列表上移除重复项目。自后往前遍历,逐个与前面项比较,如果值相同且下标相同,则移除当前项。 | |
static Integer[] unique(Integer arr[]) { | |
List<Integer> list = new ArrayList<>(Arrays.asList(arr)); | |
int l = list.size(); | |
while (l-- >) { | |
int i = l; | |
while (i-- >) { | |
if (list.get(l).equals(list.get(i))) { | |
list.remove(l); | |
break; | |
} | |
} | |
} | |
return list.toArray(new Integer[list.size()]); | |
} | |
//4. 在原有列表上移除重复项目。自前往后遍历,逐个与前面项比较,如果值相同且下标相同,则移除前面项。 | |
static Integer[] unique(Integer arr[]) { | |
List<Integer> list = new ArrayList<>(Arrays.asList(arr)); | |
int l = list.size(); | |
for (int i =; i < l; i++) { | |
for (int j =; j < i; j++) { | |
if (list.get(i).equals(list.get(j))) { | |
list.remove(i); | |
i--; | |
l--; | |
break; | |
} | |
} | |
} | |
return list.toArray(new Integer[list.size()]); | |
} | |
//5. 在原有列表上移除重复项目。自前往后遍历,逐个与后面项比较,如果值相同且下标相同,则移除当前项。 | |
static Integer[] unique(Integer arr[]) { | |
List<Integer> list = new ArrayList<>(Arrays.asList(arr)); | |
int l = list.size(); | |
for (int i =; i < l; i++) { | |
for (int j = i +; j < l; j++) { | |
if (list.get(i).equals(list.get(j))) { | |
list.remove(j); | |
i--; | |
l--; | |
break; | |
} | |
} | |
} | |
return list.toArray(new Integer[list.size()]); | |
} | |
//6. 利用hashMap属性唯一性来实现去重复。 | |
static Integer[] unique(Integer arr[]) { | |
Map<Object, Integer> map = new HashMap<Object, Integer>(); | |
for (Integer item : arr) { | |
if (map.containsKey(item)) { | |
continue; | |
} | |
map.put(item, item); | |
} | |
List<Integer> list = new ArrayList<>(map.values()); | |
return list.toArray(new Integer[list.size()]); | |
} | |
//7. 利用filter表达式,即把不符合条件的过滤掉。需要借助外部列表存储不重复项。 | |
static List<Integer> uniquenewArr = new ArrayList<>(); | |
static boolean uniquecontains(Integer item) { | |
if (uniquenewArr.indexOf(item) < 0) { | |
uniquenewArr.add(item); | |
return true; | |
} | |
return false; | |
} | |
static Integer[] unique(Integer arr[]) { | |
List<Integer> list = new ArrayList<>(Arrays.asList(arr)); | |
return list.stream().filter(UniqueArray::uniquecontains).collect(Collectors.toList()) | |
.toArray(new Integer[UniqueArray.uniquenewArr.size()]); | |
} | |
//8. 利用hashSet数据结构直接去重复项。无序非同步。 | |
static Integer[] unique(Integer arr[]) { | |
System.out.print("covert to steam first then to set: "); | |
Arrays.asList(arr).stream().collect(Collectors.toSet()).forEach(System.out::print); | |
System.out.println("ndirectly convert to set:"); | |
Set<Integer> set = new HashSet<>(Arrays.asList(arr)); | |
return new ArrayList<>(set).toArray(new Integer[set.size()]); | |
} | |
//9. 利用LinkedHashSet数据结构直接去重复项。有序链表。 | |
static Integer[] unique(Integer arr[]) { | |
Set<Integer> linkedHashSet = new LinkedHashSet<>(Arrays.asList(arr)); | |
return new ArrayList<>(linkedHashSet).toArray(new Integer[linkedHashSet.size()]); | |
} | |
//10. 利用TreeSet数据结构直接去重复项。自然排序和定制排序。 | |
static Integer[] unique(Integer arr[]) { | |
Set<Integer> treeSet = new TreeSet<>(Arrays.asList(arr)).descendingSet(); | |
return new ArrayList<>(treeSet).toArray(new Integer[treeSet.size()]); | |
} | |
//11. 提前排序,从后向前遍历,将当前项与前一项对比,如果重复则移除当前项 | |
static Integer[] unique(Integer arr[]) { | |
List<Integer> list = new ArrayList<>(Arrays.asList(arr)); | |
Collections.sort(list); | |
for (int l = list.size() -; l > 0; l--) { | |
if (list.get(l).equals(list.get(l -))) { | |
list.remove(l); | |
} | |
} | |
return new ArrayList<>(list).toArray(new Integer[list.size()]); | |
} | |
//12. 提前排序,自前往后遍历,将当前项与后一项对比,如果重复则移除当前项 | |
static Integer[] unique(Integer arr[]) { | |
List<Integer> list = new ArrayList<>(Arrays.asList(arr)); | |
Collections.sort(list, Collections.reverseOrder()); | |
int l = list.size() -; | |
for (int i =; i < l; i++) { | |
if (list.get(i).equals(list.get(i +))) { | |
list.remove(i); | |
i--; | |
l--; | |
} | |
} | |
return new ArrayList<>(list).toArray(new Integer[list.size()]); | |
} | |
//13. 转为stream,利用distinct方法去重复 | |
static Integer[] unique(Integer arr[]) { | |
List<Integer> list = new ArrayList<>(Arrays.asList(arr)); | |
list = list.stream().distinct().collect(Collectors.toList()); | |
return new ArrayList<>(list).toArray(new Integer[list.size()]); | |
} | |
//14. 双循环自右往左逐个与左侧项对比,如遇相同则跳过当前项,下一项为当前项,继续逐个与左侧项对比 | |
static Integer[] unique(Integer arr[]) { | |
int len = arr.length; | |
Integer[] result = new Integer[len]; | |
int x = len; | |
for (int i = len -; i >= 0; i--) { | |
for (int j = i -; j >= 0; j--) { | |
if (arr[i].equals(arr[j])) { | |
i--; | |
j = i; | |
} | |
} | |
// 非重复项的为唯一,追加到新数组 | |
result[--x] = arr[i]; | |
} | |
return Arrays.copyOfRange(result, x, len); | |
} | |
//15. 利用Interator来遍历List,如果不在新列表中则添加 | |
static Integer[] unique(Integer arr[]) { | |
List<Integer> list = new ArrayList<>(Arrays.asList(arr)); | |
List<Integer> result = new ArrayList<>(); | |
Iterator<Integer> it = list.iterator(); | |
while (it.hasNext()) { | |
Integer item = it.next(); | |
if (!result.contains(item)) { | |
result.add(item); | |
} | |
} | |
return new ArrayList<>(result).toArray(new Integer[result.size()]); | |
} | |
//16. 利用递归调用来去重复。递归自后往前逐个调用,当长度为1时终止。 | |
// 当后一项与前任一项相同说明有重复,则删除当前项。相当于利用自我调用来替换循环 | |
static Integer[] uniqueRecursion(Integer arr[], int len, List<Integer> result) { | |
int last = len -; | |
Integer lastItem = arr[last]; | |
int l = last; | |
boolean isRepeat = false; | |
if (len <=) { | |
result.add(, lastItem); | |
return new ArrayList<>(result).toArray(new Integer[result.size()]); | |
} | |
while (l-- >) { | |
if (lastItem.equals(arr[l])) { | |
isRepeat = true; | |
break; | |
} | |
} | |
// 如果不重复表示唯一,则添加到新数组中 | |
if (!isRepeat) { | |
result.add(, lastItem); | |
} | |
return uniqueRecursion(arr, len - 1, result); | |
} | |
//17. 利用递归调用来去重复的另外一种方式。递归自后往前逐个调用,当长度为1时终止。 | |
// 与上一个递归不同,这里将不重复的项目作为结果拼接起来 | |
static List<Integer> uniqueRecursion(List<Integer> arr, int len) { | |
if (len <=) { | |
System.out.println("last arr:" + arr); | |
return arr; | |
} | |
int last = len -; | |
int l = last -; | |
boolean isRepeat = false; | |
Integer lastItem = arr.get(last); | |
while (l >=) { | |
if (lastItem.equals(arr.get(l))) { | |
isRepeat = true; | |
break; | |
} | |
l--; | |
} | |
// 如果不重复则添加到临时列表,最后将全部结果拼接 | |
List<Integer> result = new ArrayList<>(); | |
arr.remove(last); | |
if (!isRepeat) { | |
result.add(lastItem); | |
} | |
return Stream.concat(uniqueRecursion(arr, len - 1).stream(), result.stream()).collect(Collectors.toList()); | |
} | |
//18. 双重循环,将左侧项逐个与当前项比较。如果遇到值想等则比较下标,下标相同则追加到新数组。这里与第1个方案稍微的不同。 | |
static Integer[] unique(Integer arr[]) { | |
Integer newArr[] = new Integer[arr.length]; | |
int x =; | |
for (int i =; i < arr.length; i++) { | |
int j =;; | |
for (; j < i; j++) { | |
if (arr[i].equals(arr[j])) { | |
break; | |
} | |
} | |
if (i == j) { | |
newArr[x] = arr[i]; | |
x++; | |
} | |
} | |
return Arrays.copyOf(newArr, x); | |
} |
执行测试
import java.util.*; | |
import java.util.stream.Collectors; | |
import java.util.stream.Stream; | |
public class UniqueArray { | |
// 此处省略代码... | |
public static void main(final String args[]) { | |
int arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
int[] result; | |
long startTime; | |
int arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
int[] result; | |
long startTime; | |
//. | |
System.out.println("unique start:" + Arrays.toString(arr1)); | |
startTime = System.currentTimeMillis(); | |
result = UniqueArray.unique(arr1); | |
System.out.println("unique result:" + Arrays.toString(result)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms ."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr2)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique2(arr2); | |
System.out.println("unique result:" + Arrays.toString(result2)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr2)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique3(arr3); | |
System.out.println("unique result:" + Arrays.toString(result3)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr4)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique4(arr4); | |
System.out.println("unique result:" + Arrays.toString(result4)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr5)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique5(arr5); | |
System.out.println("unique result:" + Arrays.toString(result5)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr6)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique6(arr6); | |
System.out.println("unique result:" + Arrays.toString(result6)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr7)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique7(arr7); | |
System.out.println("unique result:" + Arrays.toString(result7)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr8)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique8(arr8); | |
System.out.println("unique result:" + Arrays.toString(result8)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr9)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique9(arr9); | |
System.out.println("unique result:" + Arrays.toString(result9)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr10)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique10(arr10); | |
System.out.println("unique result:" + Arrays.toString(result10)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr11)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique11(arr11); | |
System.out.println("unique result:" + Arrays.toString(result11)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr12)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique12(arr12); | |
System.out.println("unique result:" + Arrays.toString(result12)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr13)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique13(arr13); | |
System.out.println("unique result:" + Arrays.toString(result13)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr14)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique14(arr14); | |
System.out.println("unique result:" + Arrays.toString(result14)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr15)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique15(arr15); | |
System.out.println("unique result:" + Arrays.toString(result15)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("uniqueRecursion start:" + Arrays.toString(arr16)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.uniqueRecursion1(arr16, arr16.length, new ArrayList<>()); | |
System.out.println("uniqueRecursion result:" + Arrays.toString(result16)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("uniqueRecursion start:" + Arrays.toString(arr17)); | |
startTime = System.currentTimeMillis(); | |
List<Integer> result = UniqueArray.uniqueRecursion2(new ArrayList<>(Arrays.asList(arr17)), arr17.length); | |
System.out.println("uniqueRecursion result:" + result17); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); | |
//. | |
Integer arr[] = { 1, 3, -1, 1, 2, 2, 4, 2, 2, -1 }; | |
System.out.println("unique start:" + Arrays.toString(arr18)); | |
startTime = System.currentTimeMillis(); | |
Integer result[] = UniqueArray.unique18(arr18); | |
System.out.println("unique result:" + Arrays.toString(result18)); | |
System.out.println("rntime:" + (System.currentTimeMillis() - startTime) + " ms."); |
打印结果
MacBook-Pro:unique jarry$ java --version java.0.1 2018-04-17 | |
Java(TM) SE Runtime Environment.3 (build 10.0.1+10) Java HotSpot(TM) | |
-Bit Server VM 18.3 (build 10.0.1+10, mixed mode) | |
MacBook-Pro:unique jarry$ javac UniqueArray.java | |
MacBook-Pro:unique jarry$ java UniqueArray | |
unique start:[1, 3, -1, 1, 2, 2, 4, 2, 2, -1] | |
unique result:[1, 3, -1, 2, 4] | |
time: ms. | |
unique start:[1, 3, -1, 1, 2, 2, 4, 2, 2, -1] | |
unique result:[1, 3, -1, 2, 4] | |
// ...其他省略...etc | |
time: ms. | |
uniqueRecursion start:[1, 3, -1, 1, 2, 2, 4, 2, 2, -1] | |
last arr:[] | |
uniqueRecursion result:[1, 3, -1, 2, 4] | |
time: ms. | |
unique start:[1, 3, -1, 1, 2, 2, 4, 2, 2, -1] | |
unique result:[1, 3, -1, 2, 4] |
思考
通过去重复的多种实现,其实是让我们更了解Java语言,还可以让我们根据场景采用不用方式,毕竟业务场景千差万别。你常用哪几种方式?你还有其他的实现方式吗?