Я пытаюсь удалить дубликаты из списка двойных массивов. Я хотел бы сохранить первый экземпляр дубликата, но удалить все найденные после.
Вот мой код:
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)
Вы можете использовать LINQ? Если да, то взглянули ли вы на IEnumerable.Distinct()?
Честно говоря, ваш код кажется трудным для понимания, почему вы проверяете 2 разных значения в каждом цикле? Можете ли вы предоставить нам некоторые записи и ожидаемый результат?
Вместо того, чтобы дважды зацикливаться, чтобы сначала получить элемент, а затем удалить его, возможно, ContainsDupes может вернуть дубликат (или null, если его нет). Тогда while может быть таким: double[] temp; while ((temp = ContainsDupes(list)) != null) list.Remove(temp);
@DarjanBogdan list.RemoveAt(b); удаление всего массива сделано намеренно.
@Joelius Я пытался использовать IEnumerable.Distinct(), и это не работает.
@nalnpir Длина double[] всегда равна 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, все хорошо, я преобразовал в кортеж и обратно с foreach и минуту или около того гугления
Теперь я переписал свою программу для кортежей и обнаружил, что удаление дубликатов из массива может быть легко выполнено array.Distinct().ToArray()
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);
}
Не удаляйте во время цикла, лучше сохраните повторяющиеся индексы
list.RemoveAt(b);фактически удаляет весь массивdouble[]внутриList<double[]>, а не только повторяющийся элемент. Это предназначено?