J'ai un List<>
d'objets contenant deux chaînes et un DateTime. Je veux créer une autre liste des mêmes objets contenant uniquement les derniers éléments uniques en utilisant les deux chaînes en tant que clés et la dernière valeur DateTime. En SQL, pensez ce qui suit:Boucle récursive sur List <> provoquant stackoverflow
SELECT col1, col2, MAX(datetime) FROM table GROUP BY col1, col2
Ceci donne la liste unique de col1, col2 et le dernier datetime. Donc .. J'essaye de le faire en code avec deux listes. Un avec des doublons dedans qui analysent et attrapent seulement les derniers éléments uniques pour peupler une deuxième liste. Les ensembles de données que j'ai sont énormes, donc en passant par la liste des doublons puis en vérifiant si l'élément est dans la liste unique, s'il ne l'ajoute pas, si c'est le cas, comparer les dates etc. J'ai donc pensé pouvoir parcourir de manière récursive la liste des doublons et récupérer les objets uniques trouver leur max datetime et supprimer les non max au fur et à mesure de la boucle, rendant ma liste dupliquée de plus en plus petite, accélérant ainsi les choses. (J'espère que vous me suivez toujours ..)
Donc de toute façon. J'ai écrit une boucle récursive avec deux listes, mais quand je boucle en boucle, j'obtiens un System.StackOverflowException
à propos de la 3000ème itération.
Voici mon code. Imaginez le ListWithDuplicates
est plein de données. Le ListDataItem
a plus de propriétés que j'ai omis. Mais ma question principale est pourquoi est-ce que je ne peux pas boucler le public list
de cette manière sans causer le StackOverflowException
?
using System;
using System.Net;
using System.IO;
using System.Collections.Generic;
using System.Linq;
public class RecursionTest
{
public List<listDataItem> ListWithDuplicates { get; set; }
public List<listDataItem> ListWithUniques { get; set; }
public RecursionTest()
{
Process();
}
public void Process()
{
int rowcount = 0;
int duplicates = 0;
int total = 0;
RecursiveLoopForUnique(ref rowcount, ref duplicates, ref total, "", "");
}
private void RecursiveLoopForUnique(ref int rowcount, ref int duplicates, ref int total, string col1, string col2)
{
if (rowcount > 0)
duplicates += ListWithDuplicates.RemoveAll(z => z.COL1 == col1 && z.COL2 == col2);
if (ListWithDuplicates.Count > 0)
{
foreach (listDataItem item in ListWithDuplicates)
{
rowcount++;
if (ListWithUniques.FindAll(z => z.COL1 == item.COL1 && z.COL2 == item.COL2).Count < 1)
{
ListWithUniques.Add(ListWithDuplicates.FindAll(z => z.COL1 == item.COL1 && z.COL2 == item.COL2).OrderByDescending(z => z.DATETIME).First());
col1 = item.COL1;
col2 = item.COL2;
break;
}
}
RecursiveLoopForUnique(ref rowcount, ref duplicates, ref total, col1, col2);
}
else
return;
}
public class listDataItem
{
public string COL1 { get; set; }
public string COL2 { get; set; }
public DateTime DATETIME { get; set; }
public listDataItem(string col1, string col2, DateTime datetime)
{
COL1 = col1;
COL2 = col2;
DATETIME = datetime;
}
}
}
Serait-il possible de le réécrire sans le 'break;' et vide 'return;'? Cela ressemble à demander des ennuis. – FrustratedWithFormsDesigner
@FrustratedWithFormsDesigner - vous avez raison. bon point. J'ai ajouté cette instruction if if car j'obtenais l'exception de débordement. Je n'ai pas non plus besoin de passer les valeurs col dans la fonction récursive et je pourrais les avoir supprimées après avoir quitté foreach. J'ai joué avec la fonction en essayant de venir à l'exception. aucun problème du tout ;-) – craigpj