Различный в списке‹Список‹двойной››

genesUsingCrossover — это List<List<double>>.

Я использую следующую строку кода для подсчета различных List<double> в пределах List<List<double>>:

int count = genesUsingCrossover.Distinct().Count();

и я не уверен, что это правильно. Количество элементов в genesUsingCrossover равно 1250, а также genesUsingCrossover.Distinct().Count() возвращает 1250, поэтому я предположил, что все они представляют собой отдельный список. Однако, заглянув в окно часов, я заметил, что третий и четвертый списки совпадают.

Итак, я предполагаю, что строка кода неверна. Есть ли способ улучшить его? и подсчитать количество различных элементов?

введите здесь описание изображения


person ES2018    schedule 17.07.2018    source источник
comment
Чтобы действительно получить различные значения, вам нужно использовать obj.Select(x=> propertyName).Distinct();   -  person Gericke    schedule 17.07.2018
comment
Это также может быть полезно stackoverflow.com/questions/37850167/   -  person Salah Akbari    schedule 17.07.2018
comment
Вы считаете списки или считаете двойники во всех списках?   -  person John Wu    schedule 17.07.2018


Ответы (3)


На самом деле вы не определяете, по каким критериям два списка считаются равными. Это означает, что .NET проверяет, имеют ли два списка одинаковые ссылки в памяти по умолчанию, потому что List равно reference type

Незаметно каждый список имеет свою память. Таким образом, в вашем списке 1205 элементов, он возвращает 1205 различных элементов.

Как ваше описание, я думаю, что ваши критерии: 2 списка, содержащих одинаковые элементы, должны быть равны.

Distinct может получить IEqualityComparer, поэтому идея такова: реализация IEqualityComparer для List<double>

class NumberDoubles: IEqualityComparer<List<double>>
{
    public bool Equals(List<double> x, List<double> y)
    {
        //Check whether the compared objects reference the same data.
        if (Object.ReferenceEquals(x, y)) return true;

        //Check whether any of the compared objects is null.
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        if (x.Count!= y.Count)
            return false;

        //Check whether the arrays' values are equal.
        for(int i = 0; i < x.Count; i++){
            if(x[i] != y[i])
                return false;
        }

        // If got this far, arrays are equal
        return true;
    }

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects.

    public int GetHashCode(List<double> doubleArray)
    {
        //Check whether the object is null
        if (Object.ReferenceEquals(doubleArray, null)) return 0;

        //Calculate the hash code for the array
        int hashCode = 0;
        bool isFirst = true;
        foreach(int i in doubleArray){
            if(isFirst) {
                hashCode = i;
                isFirst = false;
            }
            else
            {
                hashCode = hashCode ^ i;
            }
        }
        return hashCode;
    }
}

и ваш код:

genesUsingCrossover.Distinct(new NumberDoubles());
person Antoine V    schedule 17.07.2018
comment
Это очень неэффективно проверять. За исключением обоих списков, вам, вероятно, следует просто убедиться, что длина равна. - person johnny 5; 18.07.2018
comment
@ThierryV Я протестировал предложенное вами решение, и оно очень быстрое. Спасибо - person ES2018; 19.07.2018

List<T> не переопределяет Object.Equals, поэтому два объекта List<double> будут считаются равными, если они равны по ссылке. (Вот реализация Distinct<T>(), если вы хотите посмотреть, как это работает.) Похоже, вы хотите считать два списка равными, если элементы, из которых они состоят, равны. Для этого вы можете использовать перегрузку Distinct<T>() принимает IEqualityComparer<T>, который будет использоваться для определения равенства двух списков. Итак, в вашем случае вы можете предоставить реализацию IEqualityComparer<List<double>>, которая выражает вашу идею равенства списков.

То, как будет выглядеть эта реализация, зависит от того, когда именно вы хотите считать два списка равными. Например, должны ли они иметь один и тот же набор элементов в одном и том же порядке, или порядок не имеет значения? Есть и другие вопросы о переполнении стека, которые объясняют, как реализовать оба. В любом случае имейте в виду, что Distinct() будет вызывать вашу реализацию много раз, поэтому важно, чтобы ваш алгоритм работал хорошо. С этой целью, возможно, стоит спросить, действительно ли List<List<double>> является той структурой данных, которая вам нужна, или лучше подойдет какой-то другой вариант.

person Joe Farrell    schedule 17.07.2018

Как сказал @Joe, вы должны действительно подумать: «Действительно ли мне нужно List<List<double>>, для меня это звучит как неподходящая структура для работы. Различие может выйти из коробки с HashSet (ну, не совсем в вашем случае, но в целом каждый раз, когда кто-то видит HashSet надеюсь, это звонит в колокольчик, что желательна уникальность, в то время как List<List<double>> не обязательно показывает это).

При этом я предлагаю вам следующее решение с HashSet<List<double>>

using System;
using System.Collections.Generic;
using System.Linq;

public static class Program {
    public static void Main() {
        var hashSet = new HashSet<List<double>>(new ListComparer());

        hashSet.Add(new List<double> { 1.2d, 1.5d });
        hashSet.Add(new List<double> { 1.2d, 1.5d });

        Console.Write(hashSet.Count);
    }

    public class ListComparer : IEqualityComparer<List<double>> 

    {
        public bool Equals(List<double> x, List<double> y)
        {
            // your logic for equality
            return true;
        }

        public int GetHashCode(List<double> obj)
        {
           int hash = 0;
           unchecked {
               foreach(var d in obj) {
                   hash += d.GetHashCode();
               }
           }
           return hash;
        }  
    }
}

Имейте в виду, что метод Equals будет вызываться много раз, поэтому следует учитывать некоторые соображения производительности.

person kuskmen    schedule 17.07.2018