@somekind
Wydaje mi się, że posiadasz tą starą wersję programu (która oparta była na tym sposobie z sortowaniem i prostą pętlą). Ta nowa zawarta jest w moim ostatnim poście (oparta jest na typie Hashset, który IMO jest genialny, i też prostej pętli). BTW plik otworzyłeś w ildasm, czy w czymś innym?
AD 1)
odnośnie outputRows:
jest to zmienna typu Hashset. Dzięki użyciu tego typu mogłem zrezygnować z sortowania i dzięki temu wyjściowe wersy wstawiane są do wynikowego pliku we właściwej kolejności (tzn. nieposortowane).
odnośnie inputRows:
wiersze wczytuję z pliku do tablicy string[], ale później iteruję po nich, żeby usunąć puste wiersze, bądź wiersze zawierające tylko i wyłącznie spacje lub/i tabulatory (taki nieopisany feature). Z racji tego, że nie wiem ile będzie takich wierszy, no to inputRows jest typu List. Ale zgadzam się, że gdybym tego nie robił to najlepszym wyborem jest zwykła tablica.
AD 2) Tak na algorytm przeznaczyłem 80% całego progressbara. Na upartego mógłbym dać więcej, o ile nie nawet 100% (o czym wspominasz). Robiłem to trochę na wyczucie, bo nie wiem jak duże ma te pliki autor tematu i nie wiem jak wpłynęło by to na czas ich wczytywania i zapisywania.
Zgadzam się z tym, że tak częste wywoływanie tego zdarzenia nie ma sensu. Nie poprawiłem tego z czystego lenistwa Gdy program zamykał mi się już w czasie poniżej 2sek to stwierdziłem, że może tak na razie zostać. Ale gdybym to zmieniał to plan był, żeby zrobić dokładnie to o czym piszesz.
AD 3)
a) Tej klasy już nie ma. Uznałem, że jest ona niepotrzebna. Początkowo chciałem, żeby metoda Find zwracała obiekt tego typu, tj. DuplicateFinderResult, który przechowywałby informacje o czasie wykonania, wynikowe wiersze, itd. Ostatecznie uznałem, że lepiej będzie, gdy zachowam jedną klasę, tj. DuplicateFinder, a metoda Find nie będzie nic zwracać, a jedynie modyfikować zmienne w obrębie klasy. Ale faktycznie, gdy ta klasa jeszcze była to lepiej byłoby umieścić w niej Display().
b) Tutaj się nie zgadzam. IMO jest ok. Oto kod:
public string Display()
{
return "Duration: " + Duration.ToString() + ".\n\n"
+ "Distinct rows count: " + DistinctRowsCount.ToString() + ".\n"
+ "Duplicate rows count: " + DuplicateRowsCount.ToString() + ".\n"
+ "Total rows count: " + TotalRowsCount.ToString() + ".\n\n"
+ "Output file: " + outputFilePath + ".";
}
Choć w sumie teraz jak tak patrzę to tą metodę powinienem wywalić, a jej kod wrzucić do przeciążonej metody ToString(), co zaraz zrobię PS Dzięki za konstruktywną krytykę. DuplicateFinder.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace DuplicateFinder
{
public class DuplicateFinder
{
public delegate void ProgressChangedHandler(object sender, MyEventArgs.ProgressChangedEventArgs e);
public event ProgressChangedHandler ProgressChanged;
private string inputFilePath;
private string outputFilePath;
private Encoding fileEncoding;
private List inputRows;
private HashSet outputRows;
private DateTime startTime;
private DateTime stopTime;
public DuplicateFinder()
{
this.inputFilePath = string.Empty;
this.outputFilePath = string.Empty;
this.fileEncoding = null;
this.inputRows = new List();
this.outputRows = new HashSet();
this.startTime = DateTime.Now;
this.stopTime = DateTime.Now;
}
public DuplicateFinder(string inputFilePath, string outputFilePath, Encoding fileEncoding)
{
this.inputFilePath = inputFilePath;
this.outputFilePath = outputFilePath;
this.fileEncoding = fileEncoding;
this.inputRows = new List();
this.outputRows = new HashSet();
this.startTime = DateTime.Now;
this.stopTime = DateTime.Now;
}
public string InputFilePath
{
get { return inputFilePath; }
set { inputFilePath = value; }
}
public string OutputFilePath
{
get { return outputFilePath; }
set { outputFilePath = value; }
}
public Encoding FileEncoding
{
get { return fileEncoding; }
set { fileEncoding = value; }
}
public List InputRows
{
get { return inputRows; }
}
public HashSet OutputRows
{
get { return outputRows; }
}
public DateTime StartTime
{
get { return startTime; }
}
public DateTime StopTime
{
get { return stopTime; }
}
public TimeSpan Duration
{
get { return StopTime.Subtract(StartTime); }
}
public int TotalRowsCount
{
get { return inputRows.Count; }
}
public int DistinctRowsCount
{
get { return outputRows.Count; }
}
public int DuplicateRowsCount
{
get { return TotalRowsCount - DistinctRowsCount; }
}
public void OnProgressChanged(object sender, MyEventArgs.ProgressChangedEventArgs e)
{
if (ProgressChanged != null)
ProgressChanged(sender, e);
}
public void Clear()
{
inputRows.Clear();
outputRows.Clear();
}
public string GetDefaultOutputFilePath()
{
return Path.Combine(
Path.GetDirectoryName(inputFilePath),
Path.GetFileNameWithoutExtension(inputFilePath) + "Result" + Path.GetExtension(inputFilePath)
);
}
public void Read()
{
this.Clear();
if (File.Exists(inputFilePath))
{
string[] copy = File.ReadAllLines(inputFilePath, fileEncoding);
for (int i = 0; i < copy.Length; i++)
{
if (!string.IsNullOrEmpty(copy[i].Trim()))
inputRows.Add(copy[i]);
}
}
}
public void Write()
{
File.WriteAllLines(outputFilePath, outputRows, fileEncoding);
}
public void Find(bool ignoreCase, bool ignoreWhitespace)
{
this.OnProgressChanged(this, new MyEventArgs.ProgressChangedEventArgs(0));
// Read file (10% of total progress)
startTime = DateTime.Now;
this.Read();
this.OnProgressChanged(this, new MyEventArgs.ProgressChangedEventArgs(10));
// Find duplicates (80% of total progress)
if (ignoreCase || ignoreWhitespace)
{
HashSet set = new HashSet();
string row = string.Empty;
for (int i = 0; i < inputRows.Count; i++)
{
row = this.FindHelper(inputRows[i], ignoreCase, ignoreWhitespace);
if (!set.Contains(row))
{
set.Add(row);
outputRows.Add(inputRows[i]);
}
this.OnProgressChanged(this, new MyEventArgs.ProgressChangedEventArgs((int)(((i + 1.0) / inputRows.Count) * 80 + 10.0)));
}
set.Clear();
}
else
{
for (int i = 0; i < inputRows.Count; i++)
{
if (!outputRows.Contains(inputRows[i]))
outputRows.Add(inputRows[i]);
this.OnProgressChanged(this, new MyEventArgs.ProgressChangedEventArgs((int)(((i + 1.0) / inputRows.Count) * 80 + 10.0)));
}
}
// Write file (10% of total progress)
this.Write();
stopTime = DateTime.Now;
this.OnProgressChanged(this, new MyEventArgs.ProgressChangedEventArgs(100));
}
private string FindHelper(string row, bool ignoreCase, bool ignoreWhitespace)
{
if (ignoreCase && ignoreWhitespace)
return row.Trim().Replace(" ", "").Replace("\t", "").ToLower();
else if (ignoreCase)
return row.ToLower();
else if (ignoreWhitespace)
return row.Trim().Replace(" ", "").Replace("\t", "");
return row;
}
public override string ToString()
{
return "Duration: " + Duration.ToString() + ".\n\n"
+ "Distinct rows count: " + DistinctRowsCount.ToString() + ".\n"
+ "Duplicate rows count: " + DuplicateRowsCount.ToString() + ".\n"
+ "Total rows count: " + TotalRowsCount.ToString() + ".\n\n"
+ "Output file: " + outputFilePath + ".";
}
}
}