C # возвращает общий список объектов, используя linq - PullRequest
2 голосов
/ 02 ноября 2011

У меня есть общий список, который выглядит следующим образом:

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() { } 
}

я пытаюсь сделать следующее:

  • сначала отфильтруйте список с повторяющимися именами файлов и верните дубликаты объектов;
  • than, отфильтруйте возвращенный список с дублирующимися хеш-значениями;

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

если кто-то может мне помочь, я буду признателен. Также, пожалуйста, объясните свой код. для меня это процесс обучения.

Заранее спасибо!

[EDIT] * * тысячу двадцать-один

общий список содержит список объектов. эти объекты являются картинками. Каждое изображение имеет имя файла, хэш-значение (и некоторые другие данные, которые на данном этапе не имеют значения). некоторые изображения имеют одинаковые имена (дубликаты имен файлов). и я хочу получить список повторяющихся имен файлов из этого общего списка «пи».

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

[/ EDIT]

Ответы [ 3 ]

3 голосов
/ 02 ноября 2011

Нечто подобное должно работать. Является ли это лучшим методом, я не уверен. Это не очень эффективно, потому что для каждого элемента вы повторяете список снова, чтобы получить счетчик.

List<PicInfo> pi = new List<PicInfo>();
IEnumerable<PicInfo> filt = pi.Where(x=>pi.Count(z=>z.FileName==x.FileName)>1);

Надеюсь, код не слишком сложен, чтобы его можно было объяснить. Я всегда думаю, что в любом случае лучше решить это самостоятельно, но если что-то сбивает с толку, просто спросите, и я объясню.

Если вы хотите, чтобы второй фильтр выполнял фильтрацию для того же имени файла и того же хэша, являющегося дубликатом, то вам просто нужно расширить лямбду-счетчик в Count для проверки на хэш.

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

NB. Код написан от руки, так что простите за опечатки. Может не скомпилироваться впервые и т. Д .; -)

Изменить, чтобы объяснить код - спойлеры! ; -)

На английском языке мы хотим сделать следующее:

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

Разбивая это, перебираем список и выбираем вещи, основываясь на критериях, которые мы используем метод Where. Условием нашего метода where является

в списке более одного элемента с одинаковым именем

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

Выражение будет работать с каждым элементом списка и возвращать true, если мы хотим считать его, и false, если мы не хотим.

Имя файла, которое нас интересует, находится на x, элементе, который мы фильтруем. Поэтому мы хотим посчитать, сколько элементов имеют имя файла, такое же, как у x.FileName. Таким образом, наше выражение z=>z.FileName==x.FileName. Таким образом, z - это наша переменная в этом выражении, а x.FileName в этом контексте не меняется, пока мы перебираем z.

Затем мы, конечно, помещаем наши критерии в> 1, чтобы получить желаемое логическое значение.

Если при рассмотрении имени файла и значения хеш-значения вам нужны дубликаты, вы должны расширить часть в Count до z=>z.FileName==x.FileName && z.hashValue==x.hashValue.

Таким образом, ваш окончательный код для получения различий по обоим значениям будет:

Список пи = новый список ();
Список фильтра = pi.Where (x => pi.Count (z => z.FileName == x.FileName && z.hashValue == x.hashValue)> 1) .ToList ();

Если вы хотите, чтобы те, которые были дубликатами, рассматривали имя файла и hashvalue, то вы бы расширили часть в Count для сравнения hashValue. Поскольку это массив, вы можете использовать метод SequenceEqual , чтобы сравнить их значение по значению.

Таким образом, ваш окончательный код для получения различных значений будет:

List<PicInfo> pi = new List<PicInfo>();
List<PicInfo> filt = pi.Where(x=>pi.Count(z=>z.FileName==x.FileName && z.hashValue.SequenceEqual(x.hashValue))>1).ToList();

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

1 голос
/ 02 ноября 2011

Я думаю, вы должны использовать метод SequenceEqual для поиска дубликатов. (http://msdn.microsoft.com/ru-ru/library/bb348567.aspx). Для использования фильтра

0 голосов
/ 02 ноября 2011
        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
...