2010-12-06 10 views
4

J'ai un DataTable que je veux vérifier si les valeurs dans trois des colonnes sont uniques. Sinon, la dernière colonne doit être remplie avec le numéro de ligne de la première apparition de la combinaison de valeurs.Marquer des lignes non-uniques dans un DataTable

Par exemple, ce tableau:

ID Name LastName Age Flag 
------------------------------------- 
1  Bart Simpson  10  - 
2  Lisa Simpson  8  - 
3  Bart Simpson  10  - 
4  Ned  Flanders 40  - 
5  Bart Simpson  10  - 

devrait conduire à ce résultat:

Line Name LastName Age Flag 
------------------------------------- 
1  Bart Simpson  10  - 
2  Lisa Simpson  8  - 
3  Bart Simpson  10  1 
4  Ned  Flanders 40  - 
5  Bart Simpson  10  1 

Je résolu ce problème en itérer le DataTable avec deux boucles imbriquées for et à comparer les valeurs. Bien que cela fonctionne correctement pour une petite quantité de données, devient très lent lorsque le DataTable contient beaucoup de lignes.

Ma question est: Quelle est la meilleure solution/la plus rapide pour ce problème, étant donné que la quantité de données peut varier entre 100 et 20000 lignes, par exemple?
Existe-t-il un moyen de faire cela en utilisant LINQ? (Je ne suis pas trop familier avec cela, mais je veux apprendre!)

Répondre

0

D'accord, je pense avoir eu une réponse moi-même. Basé sur la suggestion dans la réponse de James Wiseman, j'ai essayé quelque chose avec LINQ.

Dim myErrnrFnct = Function(current, first) If(first <> current, first, 0) 
Dim myQuery = From row As DataRow In myDt.AsEnumerable _ 
         Select New With { _ 
         .LINE = row.Item("LINE"), _ 
         .NAME = row.Item("NAME"), _ 
         .LASTNAME = row.Item("LASTNAME"), _ 
         .AGE = row.Item("AGE"), _ 
         .FLAG = myErrnrFnct(row.Item("LINE"), myDt.AsEnumerable.First(Function(rowToCheck) _ 
                         rowToCheck.Item("NAME") = row.Item("NAME") AndAlso _ 
                         rowToCheck.Item("LASTNAME") = row.Item("LASTNAME") AndAlso _ 
                         rowToCheck.Item("AGE") = row.Item("AGE")).Item("LINE")) _ 
         } 

Avec cette requête, j'obtiens exactement le résultat décrit dans la Question. La fonction myErrnrFnct est nécessaire car je souhaite que la colonne Flag ait la valeur 0 s'il n'y a pas d'autre ligne avec les mêmes valeurs.

Pour obtenir un DataTable de myQuery encore, je devais ajouter quelques extensions décrites ici:
How to: Implement CopyToDataTable Where the Generic Type T Is Not a DataRow
Et puis, cette ligne fera:

Dim myNewDt As DataTable = myQuery.CopyToDataTable() 

Cela semble fonctionner très bien. Des suggestions pour faire mieux?

2

Je ne peux pas commenter comment vous pourriez faire cela en C#/VB avec une table de données, mais si vous pouviez tout déplacer en SQL , votre requête ressemblerait à ceci:

declare @t table (ID int, Name varchar(10), LastName varchar(10), Age int) 
insert into @t values (1,  'Bart' , 'Simpson',  10) 
insert into @t values (2,  'Lisa', 'Simpson' ,  8) 
insert into @t values (3,  'Bart', 'Simpson' , 10) 
insert into @t values (4,  'Ned',  'Flanders' , 40) 
insert into @t values (5 , 'Bart', 'Simpson' , 10) 

select t.*, 
(select min(ID) as ID 
    from @t t2 
    where t2.Name = t.Name 
    and t2.LastName = t.LastName 
    and t2.id < t.id) 
from @t t 

ici, j'ai défini une table à des fins de démonstration. Je suppose que vous pourriez être en mesure de traduire cela en LINQ.

+0

Merci, c'est une bonne idée avec la sous-sélection (+1). Cependant je préférerais une solution qui ne nécessite pas de SQL. Je vais essayer de faire quelque chose comme ça dans linq. –

Questions connexes