OrderBy и Вершина в LINQ с хорошей производительностью

Что хороший путь состоит в том, чтобы получить лучшие 10 записей от очень большого количества и использовать пользовательский OrderBy? Если я использую LINQ для Объектов метод OrderBy, это медленно и берет большую память, потому что он создает весь новый набор с новым порядком. Я хотел бы новый метод с подписью ниже этого, не переупорядочивает весь набор и очень быстр:

public static IEnumerable<TSource> OrderByTop<TSource, TKey>(
    IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    IComparer<TKey> comparer,
    int topCount)

Я пытался записать это, но это стало очень сложным, и я думал, что мог бы быть любой более легкий способ использовать Агрегат или что-то. Любая справка ценилась бы.

Ответ

Спасибо за справку. Я закончил с кодом ниже:

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));
}

Метод Расширения Списка SortedInsert следует:

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;
}

Для заинтересованных у меня также был keySelector Дополнительный метод для преобразования в 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));
    }
}
12
задан DRBlaise 19 January 2010 в 02:27
поделиться

4 ответа

Сервер и графический интерфейс пользователя являются отдельными компонентами. Что касается отличных графических интерфейсов SVN, то Versions.app , похоже, является фаворитом.

Редактирование для добавления следующих дополнительных приложений SVN:

http://ciaranwal.sh/2007/10/10/svn-plug-in-for-textmate (плагин TextMate)

https://www.smartsvn.com/

http://www.syncrosvnclient.com/index.html

http://www.zennaware.com/

-121--1119767-

Я следовал примеру Microsoft и не заметил, что объявления в GUI.Designer.cs (автоматически, по среде IDE) и в GUI.cs (вручную,

=== GUI.cs ===
public GUI()
{
    InitializeComponent();
    this.lvwFiles.DragDrop += new System.Windows.Forms.DragEventHandler(this.lvwFiles_DragDrop);
    this.lvwFiles.DragEnter += new System.Windows.Forms.DragEventHandler(this.lvwFiles_DragEnter);
}

=== GUI.Designer.cs ===
// 
// lvwFiles
//
... 
this.lvwFiles.DragDrop += new System.Windows.Forms.DragEventHandler(this.lvwFiles_DragDrop);
this.lvwFiles.DragEnter += new System.Windows.Forms.DragEventHandler(this.lvwFiles_DragEnter);
-121--4460381-

Агрегат - это подходящее место для начала:

SortedList<TKey, TSource> resultlist = new SortedList<TKey, TSource>();
MyBigList.Aggregate(resultlist, (aktlist,entry) => {
   aktlist.Add(entry.Key, entry);
   if (aktlist.Count > 10) aktlist.RemoveAt(10);
   return aktlist;
});

Если требуется другой компаратор, можно указать его в конструкторе SortedList .

EDIT Как указано nikie, SortedList не может содержать двойных значений. Для достижения того же эффекта можно использовать стандартный список вместе с BinureSearch :

List<TSource> resultlist = new List<TSource>();
MyBigList.Aggregate(resultlist, (aktlist, entry) => {
   int index = aktlist.BinarySearch(entry);
   if (index < 0) index = ~index;
   if (index < 10) aktlist.Insert(index, entry);
   if (aktlist.Count > 10) aktlist.RemoveAt(10);
   return aktlist;
});

В качестве параметра для BinureSearch снова можно использовать пользовательский компаратор (вместе с пользовательским выбором ключей).

8
ответ дан 2 December 2019 в 21:02
поделиться

Я думаю, что вы хотите, это действительно алгоритм выбора . Я не знаю, что LINQ - лучший способ реализации одного, так как я думаю, что он в основном заканчивается как выбор, сортировка. Вы должны быть в состоянии сделать это в O (KN), где K - это «верхний» ряд элементов, итерацией через коллекцию, отслеживать минимальный «верхний» элемент «верхний», который до настоящего времени, и если текущий элемент больше, чем Это, заменяя этот элемент с текущим элементом (и обновление нового минимального элемента). Это также экономично.

Когда вы закончите, вы можете вернуть «топ» элементы в качестве упорядоченной коллекции.

Примечание : Я предполагаю, что Linq к объектам здесь. Если вы используете LINQ для SQL, то отложил просто отложить заказ / выбирать на SQL Server и просто цепи о методах соответствующим образом, чтобы получить Выберите TOP N ... от ... заказать по ... Запрос.

Совершенно непроверенные, даже не скомпилированные. Использует общую реализацию кучи фибоначчи. Я опубликую код в моем блоге ( http://farm-fresh-code.blogspot.com ). У меня есть один висит (не уверен, если это универсально) в результате некоторых экспериментов с приоритетными очередями, которые я делал. См. Wikipedia для информации и псевдокода до тех пор.

public static IEnumerable<TSource> OrderByTop<TSource, TKey>(
    IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    IComparer<TKey> comparer,
    int topCount)
{
    // allocate enough space to hold the number of elements (+1 as a new candidate is added)
    FibonacciHeap<TKey,TSource> top = new FibonacciHeap<TKey,TSource>( comparer );
    foreach (var candidate in source) // O(n)
    {
         TKey key = keySelector(candidate);
         TKey minimum = top.AccessMinimum();
         if (minimum == null || comparer.Compare( key, minimum.Key ) > 0) // O(1)
         {
             top.Insert( key, candidate ); // O(1)
             if (top.Count >= topCount)
             {
                 top.DeleteMinimum(); // O(logk)
             }
         }
    }
    return top.ToList().Reverse().Select( t.Value ); // O(k)   
}
3
ответ дан 2 December 2019 в 21:02
поделиться

Это мой опыт того, как я научился и научил себя программированию, в частности, понимание C, это восходит к началу 1990-х, так что может быть немного античным, но страсть и драйв важны:

  • Узнайте о низкоуровневых принципах компьютера, таких как программирование EGA/VGA, вот ссылка на архив Simtel в руководстве программиста C на ПК.
  • Понимание того, как работает TSR
  • Загрузите весь архив фрагментов Боба Стаута , который представляет собой большую коллекцию кода C, которая делает только одно - изучите их и поймите, не только, что коллекция фрагментов стремится быть портативной.
  • Просмотрите в Интернете на Международном конкурсе запутанного кода C ( IOCCC ) и узнайте, как можно злоупотреблять кодом C и понять особенности языка. Худшее злоупотребление кодом - победитель! Скачайте архивы и изучите их.
  • Как и я, я любил печально известный учебник Понзо С, который помог мне чрезвычайно, к сожалению, архив очень трудно найти. Если кто-то знает, где их получить, пожалуйста, оставьте комментарий, и я внесу поправку в этот ответ, чтобы включить ссылку. Есть еще один, который я могу вспомнить - Коронадо [Дженерик?] С Учебник, опять же, моя память об этом туманная...
  • Посмотрите на журнал доктора Добба и C User Journal здесь - Я не знаю, можете ли вы по-прежнему получить их в печать, но они были классикой, может вспомнить ощущение, держа печатную копию в руке и отрываться от дома, чтобы ввести код, чтобы увидеть, что происходит!
  • Возьмите древнюю копию Turbo C v2 , которую, я полагаю, вы можете получить от borland.com и просто играть с 16-битным C программирования, чтобы почувствовать и возиться с указателями... уверен, что это древний и старый, но играть с указателями на нем хорошо.
  • Поймите и изучите Указатели, здесь к наследию Simtel.net - важнейшая ссылка на достижение C Guru 'ship для желания лучшего слова, также вы найдете множество загрузок, относящихся к языку программирования C - я помню, что на самом деле заказывал Simtel CD Archive и искал C-вещи...
-121--2444778-

Честно говоря, при изучении языка C++ я никогда не брал книгу (не пылайте, пожалуйста). Лучший совет, который я могу дать, это перейти на эту страницу и перейти к учебнику. Он охватывает большую часть языка C++ (читать: наиболее часто используемые функции) и сохраняет его максимально простым. Что касается API, которые важны... ну это вопрос предпочтения. Никто toolkit/api действительно «выиграл», но Qt, GTK- (gtkmm) и wxWidgets все большие игроки. Кроме GUI, вы, вероятно, захотите изучить либо необработанные API winsock2 и многопоточности, ЛИБО интерфейсы многопоточности и сети библиотеки повышения производительности. Я согласен, что MFC умирает, и для разработки только Windows C # принимает все большую роль (даже на linux/mono C # начинает зацепляться за... медленно).

Кроме того, лучшим способом изучения языка является кодирование.Так что не просто читать целый день - без практического опыта вы никогда не будете изучать язык. Задавайте вопросы, отвечайте на те, которые можете, и пишите учебники - для себя, если никто другой. Написание того, что вы узнали, является большим ориентиром, и процесс выпрямления всего в вашей голове, чтобы записать его таким образом, чтобы другой человек мог понять это в одиночку, является отличным способом укрепить концепции. Странным, но, казалось бы, обратным путем, я нашел лучший способ научиться программированию, помогая другим людям с их вопросами.

@ Neil- я не согласен с тем, что онлайн-учебники «плоские». Во всяком случае, стиль, которому они учат вас, может быть ориентирован на читаемость, а не на оптимизацию - что в моем-не-столь скромном-мнении является преимуществом. В своем ограниченном опыте я нашел cplusplus.com ссылку на практически все.

В частности, чтобы ответить на ваши вопросы: 1. Толстая книга не нужна. Я слышал, что более тонкие могут быть полезны в качестве краткого справочника.

  1. Это полностью субъективно и зависит от вашей цели. Сетевые и многопоточные библиотеки Boost, вероятно, являются хорошим началом.

  2. между std:: последовательность, std:: stringstream и getline (std:: istream &, std:: последовательность &). C++ поставляется с целой тонной встроенной функциональности, но не слишком раздутый/огромный/невозможно узнать. Воспользуйся этим. Весь анализ уже встроен.

-121--3329846-

Вы также можете реализовать алгоритм сортировки «разделяй и побеждай», такой как быстрая сортировка и разрыв, как только у вас есть первые k отсортированных элементов. Но предложение tvanfosson, вероятно, быстрее, если k < < N

1
ответ дан 2 December 2019 в 21:02
поделиться

Я не знаю другого решения, кроме как написать этот метод. Однако этот метод не должен быть настолько сложным.

Нужно вести отсортированный список с 10 лучшими элементами и один раз выполнить итерацию по оринигальной коллекции.

Если текущая запись во время итерации меньше, чем последняя из 10 лучших, или если у вас еще нет первых 10 записей, то вы должны добавить элемент в этот список. (И, конечно же, удалить последнюю запись из списка 10 лучших, когда это уместно)

.
2
ответ дан 2 December 2019 в 21:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: