Исключение LINQBridge IComparer - PullRequest
       26

Исключение LINQBridge IComparer

1 голос
/ 02 декабря 2011

Я использую LINQ Bridge для .NET 2.0 Framework и получаю следующую ошибку.Просто хочу первый элемент из коллекции, выбранный наугад.Не заботится о производительности в данном конкретном случае.

var result = someCollection.OrderBy(g => Guid.NewGuid()).Take(1).FirstOrDefault();

someCollection - это List<string>.Значения в коллекции являются уникальными.

Невозможно выполнить сортировку, поскольку метод IComparer.Compare () возвращает противоречивые результаты.Либо значение не сравнивается равным самому себе, либо одно значение, неоднократно сравниваемое с другим значением, дает разные результаты.x: '', тип x: 'Tuple 2', IComparer: 'System.Array+FunctorComparer 1 [LinqBridge.Tuple`2 [System.String, System.Int32]]'.

Но, похоже, работает нормальноNET 4.0.Есть ли обходной путь для этого?К сожалению, я застрял с использованием .NET 2.0 для этого сценария.

EDIT Использование последней версии LINQ Bridge (1.2)

1 Ответ

2 голосов
/ 02 декабря 2011

Еще одно обновление

Я нашел этот вопрос, который имеет ту же проблему, что и вы: Почему использование Random in Sort вызывает [Unable to sort IComparer.Compare error]
Проблема в том, что LINQBridge использует List<>.Sort внутри, что вызывает недовольство при использовании «нестабильного» алгоритма сравнения, поэтому, к сожалению, вы не можете рандомизировать этот способ.

В качестве альтернативы, вот отличный код для рандомизации или выбора случайного предмета:

    private static Random rnd = new Random();
    /// <summary>
    /// Chooses one of the items at random.
    /// 
    /// Returns default if there are no items.
    /// </summary>
    public static T RandomOrDefault<T>(this IEnumerable<T> source)
    {
        // We need the count:
        var buffer = source as ICollection<T> ?? source.ToList(); // (iterate only once)
        var itemCount = buffer.Count;
        if (itemCount == 0)
        {
            return default(T);
        }

        var index = rnd.Next(itemCount);
        return buffer.ElementAt(index);
    }

    /// <summary>
    /// Randomizes the order of the elements of a sequence. 
    /// </summary>
    public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source)
    {
        // This code is an implementation of the Fisher–Yates shuffle.
        // The code was obtained from:
        // https://stackoverflow.com/questions/1287567/c-is-using-random-and-orderby-a-good-shuffle-algorithm/1665080#1665080
        T[] elements = source.ToArray();
        // Note i > 0 to avoid final pointless iteration
        for (int i = elements.Length - 1; i > 0; i--)
        {
            // Swap element "i" with a random earlier element it (or itself)
            int swapIndex = rnd.Next(i + 1);
            yield return elements[swapIndex];
            elements[swapIndex] = elements[i];
            // we don't actually perform the swap; we can forget about the
            // swapped element because we already returned it.
        }

        // there is one item remaining that was not returned - we return it now
        yield return elements[0];
    }

Обновление

Это исключение действительно похоже на ошибку LINQBridge. Я бы порекомендовал обновить его до последней версии. Нет других очевидных причин, по которым вы видите эту проблему.

Дополнительная информация

Вы можете использовать Random вместо Guid следующим образом:

var rnd = new Random();
var result = someCollection.OrderBy(g => rnd.Next()).Take(1).FirstOrDefault();

Кроме того, .Take(1) абсолютно не нужно, когда следует .FirstOrDefault()

...