C # возвращает общий список объектов с использованием linq

#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();
 

Обратите внимание, что я не создавал промежуточный список, а просто исходил прямо из исходного списка. Вы могли бы перейти из промежуточного списка, но код будет почти таким же, если исходить из оригинала, как из отфильтрованного списка.

Комментарии:

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

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 аргументов. Я не уверен, что передать его в качестве аргументов. Это было бы именно то, что мне нужно. были проверены как имена файлов, так и хэш-значения.