[英]Remove duplicates from a large integer array using Java
您知道使用 Java 從非常大的整數數組中刪除重復值的任何時間有效的方法嗎? 數組的大小取決於登錄的用戶,但總是會超過 1500000 個未排序的值,並且有一些重復。 每個整數都包含一個介於 100000 和 9999999 之間的數字。
我嘗試將其轉換為列表,但我服務器上的堆不允許有這么多數據(我的 ISP 已對其進行了限制)。 for 循環中的常規 for 循環需要超過 5 分鍾的時間來計算。
沒有重復的數組的大小是我將存儲在我的數據庫中的大小。
幫助將不勝感激!
你也許可以使用一些設置? 我不知道 Java 的 BitSet 效率如何。 但是 9999999 可能的值只需要 9999999 / 8 = 1250000 字節 = 剛好超過 1Mb。 在遍歷值數組時,將相應的位設置為 true。 然后,您可以遍歷該位集並在發現某個位設置為 true 時輸出相應的值。
1Mb 將適合 CPU 緩存,因此這可能非常有效,具體取決於位集實現。
這也有排序數據的副作用。
而且...這是一個 O(n) 算法,因為它需要對輸入數據進行一次傳遞,集合操作是 O(1)(對於像這樣的基於數組的集合),並且輸出傳遞也是 O( m) 其中 m 是唯一值的數量,根據定義,必須 <= n。
在開始向列表添加項目之前,我會創建一個哈希集,用於存儲列表中包含的所有值。 然后只需檢查哈希集是否不包含您要添加的值。
Set<Integer> set = new HashSet<Integer>();
Collections.addAll(set, array);
您只需要一個Integer[]
數組而不是int[]
。
您可以先嘗試對數組進行排序:
int arr[] = yourarray;
Arrays.sort(arr);
// then iterate arr and remove duplicates
int[] a;
Arrays.sort(a);
int j = 0;
for (int i = 1; i < a.length; ++i) {
if (a[i] != a[j]) {
++j;
a[j] = a[i];
}
}
// now store the elements from 0 to j (inclusive - i think)
真正絕望的人可以將數組寫入磁盤並分叉sort | uniq | wc -l <infile.txt
sort | uniq | wc -l <infile.txt
sort | uniq | wc -l <infile.txt
並捕獲輸出。 如果內存仍然太緊或整數的域空間變大,則需要這樣做。 我不喜歡這個(他甚至在運行 unix!)但我的觀點是有很多方法可以完成任務。
另一個觀察結果是最小值為 100,000。 所以我們可以從最大值 9,999,999 中減去 100,000,減少域空間,從而節省一些內存。 也許 100k/8 位在事物的方案中是花生,但它本質上是免費的。
也許您可以對數據進行幾次傳遞? 例如,如果您對數據進行了 10 次傳遞,並將上述設置建議之一應用於較小的數據子集(例如,當 value mod pass# == 0 時)。 因此:
for (int i = 0 to 9) {
set = new Set()
for (each entry in the data set) {
if (entry % i == 0) {
set.add(entry)
}
}
output set
}
通過這種方式,您將為內存權衡時間(增加傳遞次數以獲得更少的內存/更多的時間,反之亦然)。
也許一個使用原語而不是對象的散列集可以完成這項工作? 有免費的實現(以前沒有使用過,但也許它有效):
http://trove4j.sourceforge.net/
http://trove4j.sourceforge.net/javadocs/gnu/trove/TIntHashSet.html
然后看起來像:
int[] newArray = new TIntHashSet(yourArray).toArray();
如果您確定整數具有合理的小值(例如總是大於零且小於 1000 或 10000),您可以嘗試這樣的技巧:
final int MAX = 100;
int[] arrayWithRepeats = {99, 0, 10, 99, 0, 11, 99};
//we are counting here integers with the same value
int [] arrayOfValues = new int[MAX+1];
int countOfUniqueIntegers = 0;
for(int i : arrayWithRepeats) {
if(arrayOfValues[i] == 0) {
countOfUniqueIntegers++;
}
arrayOfValues[i]++;
}
// you can use arrayOfValues (smaller) or convert it
// to table of unique values (more usable)
int[] arrayOfUniqueValues = new int[countOfUniqueIntegers];
int index = 0;
for(int i = 0; i<arrayOfValues.length; i++) {
if(arrayOfValues[i] != 0) {
arrayOfUniqueValues[index] = i;
index++;
}
}
//and now arrayOfUniqueValues is even sorted
System.out.println( Arrays.toString(arrayOfUniqueValues) );
輸出:[0, 10, 11, 99]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.