Jaki jest dobry sposób na zdobycie 10 najlepszych rekordów z bardzo dużej kolekcji i skorzystanie z niestandardowej opcji OrderBy? Jeśli używam metody LINQ do Objects OrderBy, jest ona wolna i zajmuje dużo pamięci, ponieważ tworzy nową kolekcję z nowym zamówieniem. Chciałbym nową metodę z podpisu poniżej, że nie zmienić kolejność całą kolekcję i jest bardzo szybki:OrderBy and Top w LINQ z dobrą wydajnością
public static IEnumerable<TSource> OrderByTop<TSource, TKey>(
IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IComparer<TKey> comparer,
int topCount)
próbowałem go napisać, ale to się bardzo skomplikowane i pomyślałem, że może być dowolny łatwiejszy sposób używając Aggregate lub czegoś takiego. Każda pomoc będzie doceniona.
Odpowiedź
Dzięki za pomoc. Skończyło się z poniższym kodzie:
public static List<TSource> OrderByTop<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IComparer<TKey> comparer,
int topCount)
{
var itemComparer = keySelector.ToIComparer(comparer);
return source.Aggregate(
new List<TSource>(topCount),
(List<TSource> list, TSource item) =>
list.SortedInsert(item, itemComparer, topCount));
}
Sposób Lista Extension SortedInsert następująco:
public static List<T> SortedInsert<T>(
this List<T> list,
T item,
IComparer<T> comparer,
int maxLength)
{
if (list.Count == maxLength)
if (comparer.Compare(item, list[maxLength - 1]) >= 0)
return list;
else
list.RemoveAt(maxLength - 1);
int insertIndex = list.BinarySearch(item, comparer);
if (insertIndex < 0)
insertIndex = ~insertIndex;
list.Insert(insertIndex, item);
return list;
}
dla zainteresowanych miałem również metodę keySelector Extension przekonwertować do IComparer.
public static IComparer<TSource> ToIComparer<TSource, TKey>(
this Func<TSource, TKey> keySelector,
IComparer<TKey> comparer)
{
return new KeySelectorToIComparerConverter<TSource, TKey>(
keySelector,
comparer);
}
private class KeySelectorToIComparerConverter<TSource, TKey>
: IComparer<TSource>
{
private readonly IComparer<TKey> comparer;
private readonly Func<TSource, TKey> keySelector;
public KeySelectorToIComparerConverter(
Func<TSource, TKey> keySelector,
IComparer<TKey> comparer)
{
this.comparer = comparer;
this.keySelector = keySelector;
}
public int Compare(TSource x, TSource y)
{
return comparer.Compare(keySelector(x), keySelector(y));
}
}
IIRC SortedList zgłasza wyjątek, gdy klucz już istnieje. – Niki
Bardzo ładne! Powinien to być RemoveAt (10) i jak nikie powiedział, że nie akceptuje duplikatów kluczy. – DRBlaise
Dzięki za wskazówki, zredagowałem odpowiedź, aby odzwierciedlić obie z nich ... – MartinStettner