ファイルのサイズと、オリジナルと複製の行の内容が必要であるという事実を考えると、ファイルを 2 回パスするのが最善だと思います。
複製の最新のライン コンテンツのみが必要な場合は、1 つのパスで済む可能性があります。オリジナルとすべての複製の行の内容を 1 回のパスで追跡することは、すべての行の内容を保存する必要があることを意味します。おそらくメモリ不足になるでしょう。
私の解決策は、同じ 2 つの BeanhashCode()
が重複していることを前提としています。使用する必要がある場合は、equals()
さらに複雑になります。
パス 1: 重複の識別
/**
* Finds the row numbers with duplicate records (using the bean's hashCode()
* method). The key of the returned map is the hashCode and the value is the
* Set of duplicate row numbers for that hashcode.
*
* @param reader
* the reader
* @param preference
* the preferences
* @param beanClass
* the bean class
* @param processors
* the cell processors
* @return the map of duplicate rows (by hashcode)
* @throws IOException
*/
private static Map<Integer, Set<Integer>> findDuplicates(
final Reader reader, final CsvPreference preference,
final Class<?> beanClass, final CellProcessor[] processors)
throws IOException {
ICsvBeanReader beanReader = null;
try {
beanReader = new CsvBeanReader(reader, preference);
final String[] header = beanReader.getHeader(true);
// the hashes of any duplicates
final Set<Integer> duplicateHashes = new HashSet<Integer>();
// the hashes for each row
final Map<Integer, Set<Integer>> rowNumbersByHash =
new HashMap<Integer, Set<Integer>>();
Object o;
while ((o = beanReader.read(beanClass, header, processors)) != null) {
final Integer hashCode = o.hashCode();
// get the row no's for the hash (create if required)
Set<Integer> rowNumbers = rowNumbersByHash.get(hashCode);
if (rowNumbers == null) {
rowNumbers = new HashSet<Integer>();
rowNumbersByHash.put(hashCode, rowNumbers);
}
// add the current row number to its hash
final Integer rowNumber = beanReader.getRowNumber();
rowNumbers.add(rowNumber);
if (rowNumbers.size() == 2) {
duplicateHashes.add(hashCode);
}
}
// create a new map with just the duplicates
final Map<Integer, Set<Integer>> duplicateRowNumbersByHash =
new HashMap<Integer, Set<Integer>>();
for (Integer duplicateHash : duplicateHashes) {
duplicateRowNumbersByHash.put(duplicateHash,
rowNumbersByHash.get(duplicateHash));
}
return duplicateRowNumbersByHash;
} finally {
if (beanReader != null) {
beanReader.close();
}
}
}
この方法の代わりに、 aCsvListReader
を使用してgetUntokenizedRow().hashCode()
- を使用することもできます。これにより、生の CSV 文字列に基づいてハッシュが計算されます (はるかに高速ですが、データに微妙な違いがあり、機能しない可能性があります)。
パス 2: 重複に関するレポート
このメソッドは、前のメソッドの出力を受け取り、それを使用して、重複するレコードと、重複する他の行をすばやく識別します。
/**
* Reports the details of duplicate records.
*
* @param reader
* the reader
* @param preference
* the preferences
* @param beanClass
* the bean class
* @param processors
* the cell processors
* @param duplicateRowNumbersByHash
* the row numbers of duplicate records
* @throws IOException
*/
private static void reportDuplicates(final Reader reader,
final CsvPreference preference, final Class<?> beanClass,
final CellProcessor[] processors,
final Map<Integer, Set<Integer>> duplicateRowNumbersByHash)
throws IOException {
ICsvBeanReader beanReader = null;
try {
beanReader = new CsvBeanReader(reader, preference);
final String[] header = beanReader.getHeader(true);
Object o;
while ((o = beanReader.read(beanClass, header, processors)) != null) {
final Set<Integer> duplicateRowNumbers =
duplicateRowNumbersByHash.get(o.hashCode());
if (duplicateRowNumbers != null) {
System.out.println(String.format(
"row %d is a duplicate of rows %s, line content: %s",
beanReader.getRowNumber(),
duplicateRowNumbers,
beanReader.getUntokenizedRow()));
}
}
} finally {
if (beanReader != null) {
beanReader.close();
}
}
}
サンプル
2 つの方法の使用例を次に示します。
// rows (2,4,8) and (3,7) are duplicates
private static final String CSV = "a,b,c\n" + "1,two,01/02/2013\n"
+ "2,two,01/02/2013\n" + "1,two,01/02/2013\n"
+ "3,three,01/02/2013\n" + "4,four,01/02/2013\n"
+ "2,two,01/02/2013\n" + "1,two,01/02/2013\n";
private static final CellProcessor[] PROCESSORS = { new ParseInt(),
new NotNull(), new ParseDate("dd/MM/yyyy") };
public static void main(String[] args) throws IOException {
final Map<Integer, Set<Integer>> duplicateRowNumbersByHash = findDuplicates(
new StringReader(CSV), CsvPreference.STANDARD_PREFERENCE,
Bean.class, PROCESSORS);
reportDuplicates(new StringReader(CSV),
CsvPreference.STANDARD_PREFERENCE, Bean.class, PROCESSORS,
duplicateRowNumbersByHash);
}
出力:
row 2 is a duplicate of rows [2, 4, 8], line content: 1,two,01/02/2013
row 3 is a duplicate of rows [3, 7], line content: 2,two,01/02/2013
row 4 is a duplicate of rows [2, 4, 8], line content: 1,two,01/02/2013
row 7 is a duplicate of rows [3, 7], line content: 2,two,01/02/2013
row 8 is a duplicate of rows [2, 4, 8], line content: 1,two,01/02/2013