2008-09-16 26 views
4

J'essaie de comparer deux grands ensembles de données à partir d'une requête SQL. À l'heure actuelle, la requête SQL est effectuée en externe et les résultats de chaque ensemble de données sont enregistrés dans son propre fichier csv. Ma petite application console C# charge les deux fichiers texte/csv et les compare pour les différences et enregistre les différences dans un fichier texte.C# Type de données pour une grande collection triée avec position?

C'est une application très simple qui charge simplement toutes les données du premier fichier dans un arraylist et fait un .compare() sur l'arraylist comme chaque ligne est lue à partir du deuxième fichier csv. Ensuite, enregistre les enregistrements qui ne correspondent pas.

L'application fonctionne mais je voudrais améliorer les performances. Je pense que je peux grandement améliorer les performances si je peux profiter du fait que les deux fichiers sont triés, mais je ne connais pas de type de données en C# qui conserve l'ordre et me permettrait de sélectionner une position spécifique. Theres un tableau de base, mais je ne sais pas combien d'éléments vont être dans chaque liste. Je pourrais avoir plus d'un million de dossiers. Y a-t-il un type de données disponible que je devrais regarder?

+0

Juste pour clarifier voulez-vous créer un fichier contenant toutes les lignes qui sont dans le deuxième fichier, mais pas dans le premier? –

+0

Peut-être un petit exemple des deux fichiers d'entrée et le résultat attendu aiderait à clarifier? –

Répondre

0

Eh bien, il existe plusieurs approches qui pourraient fonctionner. Vous pourriez écrire votre propre structure de données qui a fait cela. Ou vous pouvez essayer et utiliser SortedList. Vous pouvez également renvoyer les DataSets en code, puis utiliser .Select() sur la table. Accordé, vous auriez à faire cela sur les deux tables.

+0

MaxGeek n'a pu charger que le premier fichier dans un ensemble de données, puis parcourir le second fichier et rechercher seulement 1 jeu de données en utilisant .Select(). Ou ai-je oublié quelque chose? – Sam

+0

A contient 1,3,5 B contient 1,2,3,4. Si vous comparez seulement une direction, c.-à-d. En passant par A en B, vous ne trouverez pas 2 et 4 en B. Vous devez aussi passer en boucle B pour voir ce que A n'a pas – MagicKat

+0

Merci pour la clarification MagicKat – Sam

0

Vous pouvez facilement utiliser une liste triée pour effectuer des recherches rapides. Si les données que vous chargez sont déjà triées, les insertions dans SortedList ne doivent pas être lentes.

0

Si vous cherchez simplement à savoir si toutes les lignes de FileA sont incluses dans FileB, vous pouvez les lire et simplement comparer les flux dans une boucle.

Fichier 1 Entrée1 inscription2 Entry3

Fichier 2 Entrée1 Entry3

Vous boucle pourrait par deux compteurs et trouver omissions, allant ligne par ligne dans chaque fichier et voir si vous obtenez ce que vous avez besoin.

0

Peut-être que je ne comprends pas bien, mais l'ArrayList conservera ses éléments dans le même ordre que vous les avez ajoutés. Cela signifie que vous pouvez comparer les deux ArrayLists en un seul passage - il suffit d'incrémenter les deux index de balayage en fonction des résultats de la comparaison.

0

Une question que j'ai est avez-vous considéré "externalisant" votre comparaison. Il y a beaucoup de bons outils de diff que vous pourriez appeler. Je serais surpris s'il n'y en avait pas un qui vous laisse spécifier deux fichiers et obtenir seulement les différences. Juste une pensée.

1

System.Collections.Specialized.StringCollection vous permet d'ajouter une plage de valeurs et, en utilisant la méthode .IndexOf (string), vous permet de récupérer l'index de cet élément. Cela dit, vous pouvez probablement charger quelques octets [] à partir d'un flux de fichiers et faire des comparaisons d'octets ... ne vous souciez même pas de charger ces données dans une structure de données formelle comme StringCollection ou string []; Si tout ce que vous faites est de vérifier les différences, et vous voulez la vitesse, je voudrais décoder les différences d'octets sont là où il est.

2

Si les données de vos deux fichiers CSV sont déjà triées et ont le même nombre d'enregistrements, vous pouvez ignorer la structure de données et effectuer une analyse sur place.

StreamReader one = new StreamReader("C:\file1.csv"); 
StreamReader two = new StreamReader("C:\file2.csv"); 
String lineOne; 
String lineTwo; 

StreamWriter differences = new StreamWriter("Output.csv"); 
while (!one.EndOfStream) 
{ 
    lineOne = one.ReadLine(); 
    lineTwo = two.ReadLine(); 
    // do your comparison. 
    bool areDifferent = true; 

    if (areDifferent) 
     differences.WriteLine(lineOne + lineTwo); 
} 

one.Close(); 
two.Close(); 
differences.Close(); 
+0

C'est ce que j'ai fait auparavant sur les fichiers CSV qui sont extrêmement gros 10 millions d'enregistrements + et j'ai atteint une performance satisfaisante. De l'ordre de moins d'une minute. –

+0

Qu'en est-il si les fichiers ont un nombre de lignes différent? –

+0

Si les fichiers CSV ont un champ clé ou ID, vous pouvez les comparer, puis décider de lire une ligne supplémentaire de l'un ou de l'autre. –

0

Je pense que la raison pour laquelle tout le monde a tellement de réponses différentes est que vous n'avez pas encore assez bien spécifié votre problème pour pouvoir y répondre. Tout d'abord, cela dépend du type de différences que vous voulez suivre. Voulez-vous que les différences soient affichées comme dans un WinDiff où le premier fichier est le "original" et le second fichier est le "modifié" afin que vous puissiez lister les changements comme INSERT, UPDATE ou DELETE? Avez-vous une clé primaire qui vous permettra de faire correspondre deux lignes en tant que versions différentes du même enregistrement (lorsque les champs autres que la clé primaire sont différents)? Ou est-ce une sorte de réconciliation où vous voulez juste que la sortie de votre différence dise quelque chose comme "ENREGISTREMENT DANS FICHIER 1 ET NON FICHIER 2"?

Je pense que les réponses à ces questions aideront tout le monde à vous donner une réponse appropriée à votre problème.

0

Si vous avez deux fichiers d'un million de lignes comme indiqué dans votre publication, vous utiliserez peut-être beaucoup de mémoire. Une partie du problème de performance pourrait être que vous échantiez à partir du disque. Si vous comparez simplement la ligne 1 du fichier A à la ligne 1 du fichier B, le fichier A de la ligne 2 -> le fichier B de la ligne 2, etc., je recommanderais une technique qui ne stocke pas beaucoup en mémoire. Vous pouvez soit lire la radiation de deux flux de fichiers en tant que commentateur précédent posté et écrire vos résultats "en temps réel" comme vous les trouvez. Cela ne stockerait explicitement rien en mémoire. Vous pouvez également sauvegarder des morceaux de chaque fichier en mémoire, disons mille lignes à la fois, dans quelque chose comme une liste. Cela pourrait être réglé pour répondre à vos besoins.

1

Ceci est une adaptation du code de David Sokol à travailler avec un nombre variable de lignes, outputing les lignes qui sont dans un seul fichier, mais pas l'autre:

StreamReader one = new StreamReader("C:\file1.csv"); 
StreamReader two = new StreamReader("C:\file2.csv"); 
String lineOne; 
String lineTwo; 
StreamWriter differences = new StreamWriter("Output.csv"); 
lineOne = one.ReadLine(); 
lineTwo = two.ReadLine(); 
while (!one.EndOfStream || !two.EndOfStream) 
{ 
    if(lineOne == lineTwo) 
    { 
    // lines match, read next line from each and continue 
    lineOne = one.ReadLine(); 
    lineTwo = two.ReadLine(); 
    continue; 
    } 
    if(two.EndOfStream || lineOne < lineTwo) 
    { 
    differences.WriteLine(lineOne); 
    lineOne = one.ReadLine(); 
    } 
    if(one.EndOfStream || lineTwo < lineOne) 
    { 
    differences.WriteLine(lineTwo); 
    lineTwo = two.ReadLine(); 
    } 
} 

mise en garde standard sur le code écrit sur le haut de mon la tête s'applique - vous aurez peut-être besoin de casse de lignes spéciales dans l'une tandis que l'autre a encore des lignes, mais je pense que cette approche de base devrait faire ce que vous cherchez.

0

Pour résoudre la question 1, je vous recommande de créer un hachage pour chaque ligne. De cette façon, vous pouvez comparer les hachages rapidement et facilement en utilisant un dictionnaire.

Pour résoudre la question 2, une solution rapide et sale consisterait à utiliser un IDictionary. Utiliser itemId comme premier type de chaîne et le reste de la ligne comme deuxième type de chaîne. Vous pouvez alors trouver rapidement si un itemId existe et comparer les lignes. Cela suppose évidemment .Net 2.0+