我怎么能用扩展方法或Linq做到这一点?

时间:2010-07-09 21:05:59

标签: c# .net linq extension-methods

用我糟糕的英语解释它有点难,但我会尝试。

在下面的列表序列中,如果项目第一个字段与另一个项目第一个字段值具有相同的值但不是相同的第二个字段。结果我想收集具有相同第一个字段而不是第二个字段的项目。

它看起来很容易,但我认为它不是任何。考虑到你将在相同的序列上工作,所以有效地做这件事非常重要。

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

5 个答案:

答案 0 :(得分:6)

试试这个:

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 :(得分:1)

我想你可能想要使用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);

答案 2 :(得分:0)

你可以用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和其他一些对象),并且只有一个对象具有第二个参数。

我确信这可以改进。

答案 3 :(得分:0)

以下是我提出的建议:

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
}

答案 4 :(得分:0)

我认为你可以通过在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.second:10,y.second:0,x.ID:1,y.ID:7

首先找到:1,x.second:11,y.second:20,x.ID:2,y.ID:5

首先找到:2,x.second:12,y.second:30,x.ID:3,y.ID:6

首先找到:0,x.second:10,y.second:0,x.ID:4,y.ID:7

首先找到:1,x.second:20,y.second:11,x.ID:5,y.ID:2

首先找到:1,x.second:20,y.second:11,x.ID:5,y.ID:8

首先找到:2,x.second:30,y.second:12,x.ID:6,y.ID:3

首先找到:2,x.second:30,y.second:12,x.ID:6,y.ID:9

首先找到:0,x.second:0,y.second:10,x.ID:7,y.ID:1

首先找到:0,x.second:0,y.second:10,x.ID:7,y.ID:4

首先找到:1,x.second:11,y.second:20,x.ID:8,y.ID:5

首先找到:2,x.second:12,y.second:30,x.ID:9,y.ID:6