Удаление дубликатов из List<double[]>

Я пытаюсь удалить дубликаты из списка двойных массивов. Я хотел бы сохранить первый экземпляр дубликата, но удалить все найденные после.

Вот мой код:

private static List<double[]> RemoveDupes(List<double[]> locData)
    {
        List<double[]> list = locData;
        while (ContainsDupes(list))
            for (int a = 0; a < list.Count; a++)
                for (int b = 0; b < list.Count; b++)
                    if (a != b && list[a][0] == list[b][0] && list[a][1] == list[b][1])
                        list.RemoveAt(b);

        return list;
    }
private static bool ContainsDupes(List<double[]> list)
    {
        for (int a = 0; a < list.Count; a++)
            for (int b = 0; b < list.Count; b++)
                if (a != b && list[a][0] == list[b][0] && list[a][1] == list[b][1])
                    return true;
        return false;
    }

Этот метод работает почти все время, но он медленный, а в крайних случаях (1 из нескольких тысяч) он приводит к сбою моей программы с исключением индекса в строке 6. Я не могу придумать другого способа сделать это, поэтому любая помощь будет оценена.

Вход:

{{45.5, 23.6}, {34.54, 98.34}, {45.5, 23.6}}

Желаемый результат:

{{45.5, 23.6}, {34.54, 98.34}}

(длина double[] всегда равна 2)

list.RemoveAt(b); фактически удаляет весь массив double[] внутри List<double[]>, а не только повторяющийся элемент. Это предназначено?
Darjan Bogdan 27.05.2019 15:26

Вы можете использовать LINQ? Если да, то взглянули ли вы на IEnumerable.Distinct()?

Joelius 27.05.2019 15:27

Честно говоря, ваш код кажется трудным для понимания, почему вы проверяете 2 разных значения в каждом цикле? Можете ли вы предоставить нам некоторые записи и ожидаемый результат?

nalnpir 27.05.2019 15:28

Вместо того, чтобы дважды зацикливаться, чтобы сначала получить элемент, а затем удалить его, возможно, ContainsDupes может вернуть дубликат (или null, если его нет). Тогда while может быть таким: double[] temp; while ((temp = ContainsDupes(list)) != null) list.Remove(temp);

StackLloyd 27.05.2019 15:33

@DarjanBogdan list.RemoveAt(b); удаление всего массива сделано намеренно.

TrueCP5 27.05.2019 15:36

@Joelius Я пытался использовать IEnumerable.Distinct(), и это не работает.

TrueCP5 27.05.2019 15:37

@nalnpir Длина double[] всегда равна 2. Я отредактировал сообщение с желаемым результатом.

TrueCP5 27.05.2019 15:39

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

Joelius 27.05.2019 15:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
8
137
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

Например, вы можете определить набор пар:

List<(double, double)> pairs = new List<(double, double)>(); //C# 7.1+

List<Tuple<double, double>> pairsCollection = new List<Tuple<double, double>>(); // C# 7 or less

Посейте его таким образом:

pairs.Add((45.5, 23.6));
pairs.Add((34.54, 98.34));
pairs.Add((45.5, 23.6));

А затем просто используйте метод Distinct, чтобы удалить дубликаты:

pairs.Distinct();

Это выведет:

{{45.5, 23.6}, {34.54, 98.34}}

Кроме того, если вы не можете изменить тип данных, вы можете спроецировать коллекцию на коллекцию пар и отличить ее:

List<double[]> collection = new List<double[]>()
{
    new double[]{45.5, 23.6},
    new double[]{34.54, 98.34},
    new double[]{45.5, 23.6}
};
var pairs = collection.Select(pa => (pa[0], pa[1])); 
var distinctPairs = pairs.Distinct();

Второй — отличное и чистое решение, однако в конце концов ОП все равно понадобится способ вернуться к List<double[]>.

StackLloyd 27.05.2019 16:02

@StackLloyd, все хорошо, я преобразовал в кортеж и обратно с foreach и минуту или около того гугления

TrueCP5 27.05.2019 16:07

Теперь я переписал свою программу для кортежей и обнаружил, что удаление дубликатов из массива может быть легко выполнено array.Distinct().ToArray()

TrueCP5 18.07.2019 12:08

Вы можете использовать https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sequenceequal?redirectedfrom=MSDN&view=netframework-4.8#System_Linq_Enumerable_SequenceEqual__1_System_Collections_Generic_IEnumerable___0__System_Collections_Generic_IEnumerable___0__

var l = new List<int[]>(){
            new int[]{5,4,3},
            new int[]{5,4,3},
            new int[]{5,4,2},
            };

            var indexStore = new List<int>();

            for (int i = 0; i < l.Count - 1; i++)
            {
                for (int x = i + 1; x < l.Count-1; x++)
                {
                    if (l[i].SequenceEqual(l[x]))
                    {
                        indexStore.Add(x);
                    }
                }
            }

            foreach (var index in indexStore)
            {
                l.RemoveAt(index);
            }

Не удаляйте во время цикла, лучше сохраните повторяющиеся индексы

Другие вопросы по теме