2009-08-07 19 views
6

Biorąc pod uwagę plik wejściowy z liniami tekstu, chcę, aby zduplikowane linie zostały zidentyfikowane i usunięte. Proszę pokazać prosty fragment C#, który to zapewnia.Usunąć zduplikowane linie z pliku tekstowego?

+0

Istnieje wiele metod, niektóre łatwiejsze do wdrożenia niż inni. Podejście, które należy podjąć, może zależeć od wielkości pliku tekstowego i oczekiwanej liczby pasujących wierszy. Czy możesz opisać konkretny problem, który próbujesz rozwiązać? Dzięki :) –

+0

. . . i pożądaną wydajność. –

Odpowiedz

18

Należy to zrobić (i skopiuje z dużych plików).

Należy pamiętać, że to tylko usuwa zduplikowane kolejnych linie, czyli

a 
b 
b 
c 
b 
d 

skończy się jak

a 
b 
c 
b 
d 

Jeśli chcesz żadnych duplikatów wszędzie, trzeba zachować zestaw linie, które już widziałeś.

using System; 
using System.IO; 

class DeDuper 
{ 
    static void Main(string[] args) 
    { 
     if (args.Length != 2) 
     { 
      Console.WriteLine("Usage: DeDuper <input file> <output file>"); 
      return; 
     } 
     using (TextReader reader = File.OpenText(args[0])) 
     using (TextWriter writer = File.CreateText(args[1])) 
     { 
      string currentLine; 
      string lastLine = null; 

      while ((currentLine = reader.ReadLine()) != null) 
      { 
       if (currentLine != lastLine) 
       { 
        writer.WriteLine(currentLine); 
        lastLine = currentLine; 
       } 
      } 
     } 
    } 
} 

Zauważ, że ten zakłada Encoding.UTF8 i że chcesz używać plików. Łatwo uogólnić jako metoda jednak:

static void CopyLinesRemovingConsecutiveDupes 
    (TextReader reader, TextWriter writer) 
{ 
    string currentLine; 
    string lastLine = null; 

    while ((currentLine = reader.ReadLine()) != null) 
    { 
     if (currentLine != lastLine) 
     { 
      writer.WriteLine(currentLine); 
      lastLine = currentLine; 
     } 
    } 
} 

(. Należy pamiętać, że to niczego nie zamyka - rozmówca powinien zrobić)

Oto wersja, która usunie wszystkie duplikatów, zamiast tylko kolejne z nich:

static void CopyLinesRemovingAllDupes(TextReader reader, TextWriter writer) 
{ 
    string currentLine; 
    HashSet<string> previousLines = new HashSet<string>(); 

    while ((currentLine = reader.ReadLine()) != null) 
    { 
     // Add returns true if it was actually added, 
     // false if it was already there 
     if (previousLines.Add(currentLine)) 
     { 
      writer.WriteLine(currentLine); 
     } 
    } 
} 
28

Dla małych plików:

string[] lines = File.ReadAllLines("filename.txt"); 
File.WriteAllLines("filename.txt", lines.Distinct().ToArray()); 
+0

Zastanawiam się, jak obsługuje on .Distinct() na T []. – user7116

+0

Wygląda na to, że Distinct używa wewnętrznej klasy Set, która wydaje się być parą w dół klasy HashSet. Pod warunkiem, że "linie" nie są strasznie duże w.r.t. pamięć ta powinna działać bardzo dobrze. – user7116

2

przez długi pliku (a nie kolejnych powielania) Chciałbym skopiować pliki linia po linii zabudowy tabeli odnośników hash // pozycja jako poszedłem.

Podczas kopiowania każdej linii należy sprawdzić wartość mieszaną, jeśli występuje kolizja, sprawdź, czy linia jest taka sama i przejdź do następnej. (

Tylko warto dla dość dużych plików chociaż.

2

Oto podejście strumieniowe, które powinny ponieść mniejsze obciążenie niż przeczytaniu wszystkich unikatowych ciągów w pamięci.

var sr = new StreamReader(File.OpenRead(@"C:\Temp\in.txt")); 
    var sw = new StreamWriter(File.OpenWrite(@"C:\Temp\out.txt")); 
    var lines = new HashSet<int>(); 
    while (!sr.EndOfStream) 
    { 
     string line = sr.ReadLine(); 
     int hc = line.GetHashCode(); 
     if(lines.Contains(hc)) 
      continue; 

     lines.Add(hc); 
     sw.WriteLine(line); 
    } 
    sw.Flush(); 
    sw.Close(); 
    sr.Close(); 
+1

Wymaga mniej pamięci, ale generuje również niepoprawne dane wyjściowe w przypadku kolizji mieszania. –

0

Jestem nowy .net & mieć napisane coś prostszego, może nie być bardzo wydajne. Wypełnij za darmo, aby podzielić się swoimi przemyśleniami

class Program 
{ 
    static void Main(string[] args) 
    { 
     string[] emp_names = File.ReadAllLines("D:\\Employee Names.txt"); 
     List<string> newemp1 = new List<string>(); 

     for (int i = 0; i < emp_names.Length; i++) 
     { 
      newemp1.Add(emp_names[i]); //passing data to newemp1 from emp_names 
     } 

     for (int i = 0; i < emp_names.Length; i++) 
     { 
      List<string> temp = new List<string>(); 
      int duplicate_count = 0; 

      for (int j = newemp1.Count - 1; j >= 0; j--) 
      { 
       if (emp_names[i] != newemp1[j]) //checking for duplicate records 
        temp.Add(newemp1[j]); 
       else 
       { 
        duplicate_count++; 
        if (duplicate_count == 1) 
         temp.Add(emp_names[i]); 
       } 
      } 
      newemp1 = temp; 
     } 
     string[] newemp = newemp1.ToArray(); //assigning into a string array 
     Array.Sort(newemp); 
     File.WriteAllLines("D:\\Employee Names.txt", newemp); //now writing the data to a text file 
     Console.ReadLine(); 
    } 
} 
+0

Jedna myśl: byłoby przydatne, gdybyś mógł skomentować swój kod, aby wyjaśnić, co robisz (i dlaczego) - to pomoże innym zrozumieć Twoją metodologię i zastosować ją w swoich sytuacjach w przyszłości. –

Powiązane problemy