Как я могу сделать это с помощью методов Extensions или Linq? - PullRequest
0 голосов
/ 10 июля 2010

Это немного сложно объяснить моим плохим английским, но я попробую.

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

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

class MyClass
{
    public int first;
    public int second;
}
List<MyClass> sequence = new List<MyClass>();

Ответы [ 5 ]

6 голосов
/ 10 июля 2010

Попробуйте это:

List<MyClass> sequence = new List<MyClass>()
{
    new MyClass{ First = 1, Second = 10 },
    new MyClass{ First = 1, Second = 10 },
    new MyClass{ First = 2, Second = 11 },
    new MyClass{ First = 2, Second = 12 }
};

var doesntMatch = sequence
    .GroupBy(i => i.First)
    .Select(g => new
        { 
            Key = g.Key, 
            Values = g.Select(i => i.Second).Distinct()
        })
    .Where(i => i.Values.Count() > 1);
foreach (var i in doesntMatch)
{
    Console.WriteLine(
        "First = {0} contains {1} distinct values: {2}", i.Key, i.Values.Count(),
        String.Join(", ", i.Values.Select(n => n.ToString()).ToArray()));
}

// output: "First = 2 contains 2 distinct values: 11, 12"
1 голос
/ 10 июля 2010

Я думаю, вы можете использовать GroupBy.

var sequence = new List<MyClass>() 
{
    new MyClass() { First = 1, Second = 2 },
    new MyClass() { First = 1, Second = 3 },
    new MyClass() { First = 1, Second = 4 },
    new MyClass() { First = 3, Second = 2 },
    new MyClass() { First = 5, Second = 4 },
};

var group1 = sequence.GroupBy(x => x.First);
0 голосов
/ 10 июля 2010

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

class Program
{
    class MyClass
    {
        public int ID;
        public int first;
        public int second;
    }

    static void Main(string[] args)
    {
        // create a sequence containing example data
        List<MyClass> sequence = new List<MyClass>();
        sequence.AddRange(new MyClass[] {
            new MyClass { ID = 1, first = 0, second = 10 },
            new MyClass { ID = 2, first = 1, second = 11 },
            new MyClass { ID = 3, first = 2, second = 12 },
            new MyClass { ID = 4, first = 0, second = 10 },
            new MyClass { ID = 5, first = 1, second = 20 },
            new MyClass { ID = 6, first = 2, second = 30 },
            new MyClass { ID = 7, first = 0, second = 0 },
            new MyClass { ID = 8, first = 1, second = 11 },
            new MyClass { ID = 9, first = 2, second = 12 },
        });

        var matches = from x in sequence
                      join y in sequence // join sequence to itself
                      on x.first equals y.first // based on the first field
                      where
                        !object.ReferenceEquals(x, y) // avoid matching an item to itself
                        && x.second != y.second // find cases where the second field is not equal
                      select new { X = x, Y = y }; // return a "tuple" containing the identified items

        foreach (var match in matches)
        {
            Console.WriteLine("Found first:{0}, x.second:{1}, y.second:{2}, x.ID:{3}, y.ID:{4}", match.X.first, match.X.second, match.Y.second, match.X.ID, match.Y.ID);
        }
    }
}

Вывод этой программы следующий:

Сначала найдено: 0, секунда x: 10, секунда y: 0, идентификатор id: 1, идентификатор id: 7

Первый найден: 1, х.секунда: 11, у.секунда: 20, х.ID:2, у.ID: 5

Сначала найдено: 2, х.секунда: 12, у.секунда: 30, х.ID:3, у.ID:6

Первый найден: 0, секунда x: 10, секунда y: 0, идентификатор ID: 4, идентификатор id: 7

Найдено первым: 1, х.секунда: 20, г.секунда: 11, х.ID:5, y.ID:2

Сначала найдено: 1, х.секунда: 20, у.секунда: 11, х.ID:5, у.ID:8

Сначала найдено: 2, х.секунда: 30, у.секунда: 12, х.ID:6, у.ID:3

Обнаружено первое: 2, х.секунда: 30, у.секунда: 12, х.ID:6, у.ID:9

Сначала найдено: 0, секунда x: 0, секунда y: 10, идентификатор ID: 7, идентификатор id: 1

Сначала найдено: 0, х.секунда: 0, у.секунда: 10, х.ID:7, у.ID:4

Обнаружено первое: 1, х.секунда: 11, у.секунда: 20, х.ID:8, у.ID:5

Обнаружено первое: 2, х.секунда: 12, у.секунда: 30, х.ID:9, у.ID:6

0 голосов
/ 10 июля 2010

Вот что я придумал:

class MyClass
{
    public int First;
    public int Second;
}

void Main()
{ 
    List<MyClass> sequence = new List<MyClass>()
    {
        new MyClass{ First = 1, Second = 10 },
        new MyClass{ First = 1, Second = 10 },
        new MyClass{ First = 1, Second = 11 },
        new MyClass{ First = 2, Second = 11 },
        new MyClass{ First = 2, Second = 12 },
        new MyClass{ First = 3, Second = 10 }
    };

    var lonelyItems = sequence

        // remove all those which don't match First
        .GroupBy(x => x.First).Where(g => g.Count() > 1)

        // keep only one for each Second
        .SelectMany(g => g.GroupBy(x => x.Second)).Select(g => g.First()); 

    foreach (var x in lonelyItems)
        Console.WriteLine(x);

    // output:
    // 1,10
    // 1,11
    // 2,11
    // 2,12
}
0 голосов
/ 10 июля 2010

вы можете сделать что-то подобное с linq, если вы MyClass объекты в некоторой коллекции

Допустим, list<MyClass> myList для примера

     (from o in myList where 
(from o1 in myList where o1.first == o.first select o1).Count == 2 
&& (from o2 in  myList where o2.second == o.second select o2).count == 1 
    select o)

Это говорит о том, что нужно получить все объекты из моего списка, где есть как минимум 2 объекта с первым параметром (o и некоторый другой объект) и только один объект с вторым параметром.

Я уверен, что это можно улучшить.

...