J’ai 9 Go de données et je ne veux que 10 lignes. Quand je fais:
data.OrderBy(datum => datum.Column1) .Take(10) .ToArray();
Je reçois une OutOfMemoryException
. Je souhaite utiliser une méthode OrderByAndTake
, optimisée pour une consommation de mémoire inférieure. C’est facile à écrire, mais je suppose que quelqu’un l’a déjà fait. Où puis-je le trouver.
Edit : C’est Linq-to-objects. Les données proviennent d’un fichier. Chaque ligne peut être supprimée si sa valeur pour Column1
est inférieure à la liste actuelle des 10 valeurs les plus importantes.
Je suppose que vous faites cela dans Linq to Objects. Vous pourriez faire quelque chose comme …
var best = data .Aggregate(new List(), (soFar, current) => soFar .Concat(new [] { current }) .OrderBy(datum => datum.Column1) .Take(10) .ToList());
De cette manière, il n’est pas nécessaire de conserver tous les éléments dans une nouvelle collection sortingée, mais uniquement les 10 meilleurs articles qui vous intéressent.
C’était le moins de code possible. Puisque vous savez que la liste soFar
est sortingée, il est possible d’optimiser les emplacements où / si insérer du current
. Je n’avais pas envie de faire TOUT le travail pour vous. 😉
PS: remplacez T
par votre type.
EDIT: En y réfléchissant, le moyen le plus efficace serait en fait une vieille méthode simple qui compare chaque élément à la liste des 10 meilleurs.
Il en ressort: OrderBy est un sorting qui nécessite de stocker tous les éléments (l’exécution différée est annulée).
Cela devrait fonctionner efficacement lorsque les data
sont un IQueryable, puis c’est à la firebase database.
// just 4 fun public static IEnumerable TakeDistinctMin(this IEnumerable @this, int n, Func selector) where TKey: IComparable { var tops = new SortedList(n+1); foreach (var item in @this) { TKey k = selector(item); if (tops.ContainsKey(k)) continue; if (tops.Count < n) { tops.Add(k, item); } else if (k.CompareTo(tops.Keys[tops.Count - 1]) < 0) { tops.Add(k, item); tops.RemoveAt(n); } } return tops.Values; }
Pour commander un ensemble d’objects non ordonnés, vous devez tous les regarder, non?
Je ne vois pas comment vous pourriez éviter d’parsingr les 9 Go de données pour obtenir les 10 premiers ordres d’une certaine manière, à moins que les 9 Go de données aient déjà été commandés de cette manière ou s’il existe des index ou d’autres données auxiliaires structures qui pourraient être utilisées.
Pourriez-vous fournir un peu plus de détails sur votre question? Vous interrogez une firebase database utilisant LINQ to SQL ou Entity Framework ou un autre O / RM?
Vous pouvez utiliser quelque chose comme ceci avec un comparateur de projection :
public static IEnumerable OrderAndTake (this IEnumerable seq,int count,IComparer comp) { var resultSet=new SortedSet (comp); foreach(T elem in seq) { resultSet.Add(elem); if(resultSet.Count>count) resultSet.Remove(resultSet.Max); } return resultSet.Select(x=>x); }
Le temps d’exécution doit être O(log(count)*seq.Count())
et espace O(min(log(count),seq.Count()))
Un problème est que cela va casser si vous avez deux éléments pour lesquels comp.Compare(a,b)==0
puisque l’ensemble ne permet pas les entrées en double.