#c# #linq #filter #generic-list
#c# #linq #Фильтр #общий список
Вопрос:
я получил общий список, который выглядит следующим образом:
List<PicInfo> pi = new List<PicInfo>();
PicInfo — это класс, который выглядит следующим образом:
[ProtoContract]
public class PicInfo
{
[ProtoMember(1)]
public string fileName { get; set; }
[ProtoMember(2)]
public string completeFileName { get; set; }
[ProtoMember(3)]
public string filePath { get; set; }
[ProtoMember(4)]
public byte[] hashValue { get; set; }
public PicInfo() { }
}
что я пытаюсь сделать, так это:
- сначала отфильтруйте список с повторяющимися именами файлов и верните повторяющиеся объекты;
- затем отфильтруйте возвращенный список с повторяющимися значениями хэша;
я могу найти только примеры того, как это сделать, которые возвращают анонимные типы. но мне нужно, чтобы это был общий список.
если кто-то может мне помочь, я был бы признателен. также, пожалуйста, объясните свой код. для меня это процесс обучения.
заранее спасибо!
[ПРАВИТЬ]
общий список содержит список объектов. эти объекты являются изображениями. у каждого изображения есть имя файла, хэш-значение (и еще некоторые данные, которые на данный момент не имеют значения). некоторые изображения имеют одинаковые имена (повторяющиеся имена файлов). и я хочу получить список повторяющихся имен файлов из этого общего списка «pi».
Но эти изображения также имеют хэш-значение. из идентичных имен файлов мне нужен другой список идентичных имен файлов, которые также имеют идентичные хэш-значения.
[/ ПРАВИТЬ / ПРАВИТЬ код]
Комментарии:
1. Вы должны лучше описать свой ввод вывод. Что вы подразумеваете под фильтрацией списка по повторяющимся именам файлов? Какую форму должен иметь результат?
Ответ №1:
Что-то вроде этого должно сработать. Я не уверен, является ли это лучшим методом. Это не очень эффективно, потому что для каждого элемента вы снова перебираете список, чтобы получить количество.
List<PicInfo> pi = new List<PicInfo>();
IEnumerable<PicInfo> filt = pi.Where(x=>pi.Count(z=>z.FileName==x.FileName)>1);
Я надеюсь, что код не слишком сложный, чтобы нуждаться в объяснении. Я всегда думаю, что лучше всего разобраться с этим самостоятельно, но если что-то сбивает с толку, просто спросите, и я объясню.
Если вы хотите, чтобы второй фильтр фильтровал для того же имени файла и того же хэша, который является дубликатом, тогда вам просто нужно расширить лямбда-код в графе, чтобы также проверить хэш.
Очевидно, что если вам нужны только имена файлов в конце, то достаточно легко сделать a Select
, чтобы получить просто перечислимый список этих имен файлов, возможно, с помощью a Distinct
, если вы хотите, чтобы они появлялись только один раз.
ПРИМЕЧАНИЕ. Код написан вручную, поэтому прошу прощения за опечатки. Может не скомпилироваться с первого раза и т.д. 😉
Редактировать, чтобы объяснить код — спойлеры! 😉
На английском языке мы хотим сделать следующее:
для каждого элемента в списке мы хотим выбрать его тогда и только тогда, когда в списке есть более одного элемента с одинаковым именем файла.
Разбивая это на итерации по списку и выбирая объекты на основе критериев, мы используем метод Where . Условием нашего метода where является
в списке более одного элемента с одинаковым именем файла
для этого нам явно нужно подсчитать список, поэтому мы используем pi.Подсчитайте. Однако у нас есть условие, что мы считаем только, если имя файла совпадает, поэтому мы передаем выражение, чтобы указать ему только для подсчета этих вещей.
Выражение будет работать с каждым элементом списка и возвращать true, если мы хотим его посчитать, и false, если мы этого не хотим.
Имя файла, которое нас интересует, находится в x , элементе, который мы фильтруем. Итак, мы хотим подсчитать, сколько элементов имеют имя файла, совпадающее с x.FileName . Таким образом, наше выражение z=>z.FileName==x.FileName
. Итак, z — это наша переменная в этом выражении, а x.Имя файла в этом контексте не меняется, когда мы перебираем z .
Затем мы, конечно, помещаем наши критерии в > 1, чтобы получить желаемое логическое значение.
Если вы хотите, чтобы те, которые являются дубликатами при рассмотрении имени файла и хэш-значения, вы бы расширили часть в подсчете, чтобы быть z=>z.FileName==x.FileName amp;amp; z.hashValue==x.hashValue
.
Итак, ваш окончательный код для получения различий для обоих значений будет:
Список pi = новый список();
Список filt = pi.Где(x=>pi.Count(z=>z.FileName==x.FileName amp;amp; z.hashValue==x.hashValue)>1).ToList();
Если вам нужны те, которые являются дубликатами при рассмотрении имени файла и хэш-значения, тогда вы должны расширить часть в графе, чтобы также сравнить хэш-значение. Поскольку это массив, вы захотите использовать метод SequenceEqual для сравнения их значение по значению.
Итак, ваш окончательный код для получения различий для обоих значений будет:
List<PicInfo> pi = new List<PicInfo>();
List<PicInfo> filt = pi.Where(x=>pi.Count(z=>z.FileName==x.FileName amp;amp; z.hashValue.SequenceEqual(x.hashValue))>1).ToList();
Обратите внимание, что я не создавал промежуточный список, а просто исходил прямо из исходного списка. Вы могли бы перейти из промежуточного списка, но код будет почти таким же, если исходить из оригинала, как из отфильтрованного списка.
Комментарии:
2. Что вы получите из приведенного выше кода, так это IEnumerable<PicInfo> со всеми объектами PicInfo с повторяющимся именем файла. Это не даст вам одну копию. Я не уверен, какой общий список вам нужен. Общий список имен файлов, предположительно, будет List<string>, но я не уверен, почему вы хотите, чтобы они появлялись несколько раз. Если вам нужен список PicInfo, вам просто нужно вызвать ToList(), чтобы получить его.
3. да, мне нужна информация о picinfo. итак, я сделаю . Функция Tolist() в конце. итак, с помощью этой строки я получаю все объекты с одинаковым именем файла, верно?
4. Ага. Я обновлю вопрос объяснением того, как это работает, если у вас все еще возникают проблемы с его выполнением. 🙂
5. @Yustme: Ах, я забыл, что это массив. У него будут проблемы с определением равенства. Вероятно, вы хотите использовать SequenceEquals ( msdn.microsoft.com/en-us/library/bb348567.aspx ) для сравнения байтовых массивов. См. Обновление в ответе.
Ответ №2:
Я думаю, вам нужно использовать метод SequenceEqual для поиска дубликатов (http://msdn.microsoft.com/ru-ru/library/bb348567.aspx ). Для использования фильтра
Ответ №3:
var p = pi.GroupBy(rs => rs.fileName) // group by name
.Where(rs => rs.Count() > 1) // find group whose count greater than 1
.Select(rs => rs.First()) // select 1st element from each group
.GroupBy(rs => rs.hashValue) // now group by hash value
.Where(rs => rs.Count() > 1) // find group has multiple values
.Select(rs => rs.First()) // select first element from group
.ToList<PicInfo>() // make the list of picInfo of result
Комментарии:
1. Если есть дубликаты, я хочу, чтобы были возвращены все они, а не только один из них. Разве это не то, что будет делать ‘First()’? просто вернуть один из дубликатов? Кроме того, это анонимный тип. Это должен быть общий список.
2. @Yustme: «Кроме того, это анонимный тип. Это должен быть общий список.» => Затем используйте в конце запроса Linq:
ToList<PicInfo>()
.3. я понял это, спасибо, но как насчет функции «First»? возвращает ли это только 1 элемент или оба, если имена и значения хэша равны?
4. Метод GroupBy вернет последовательность групп, каждая из которых состоит из объектов с одинаковым именем файла. Таким образом, rs.First получит первую PicInfo для данной группы. Это означает, что в итоге вы получите только один PicInfo для каждого имени файла, что, я думаю, не то, что вам нужно. Я подозреваю, что есть метод, который возьмет их все и вернет их в последовательность, но я не могу понять, что это такое.
5. я пробовал All(), но эта функция не принимает 0 аргументов. Я не уверен, что передать его в качестве аргументов. Это было бы именно то, что мне нужно. были проверены как имена файлов, так и хэш-значения.