Linq中有多个列

时间:2010-11-07 22:03:55

标签: c# linq

问题:如何简化下面的代码,因为我的目标是在事物类中有30个不同的属性。

代码在'thing'属性中寻找唯一性。

public class thing
{
    public string Name { get; set; }
    public string Colour { get; set; }
    public string Position { get; set; }
    public string Height { get; set; }
}

public List<thing> SeeIfAnyInListHaveAUniqueSingleColumn(List<thing> listOfThings)
    {
        // try colour
        IEnumerable<IGrouping<string, thing>> thingQuery2 = from t in listOfThings
                                                            group t by t.Colour;
        List<thing> listOfThingsFound = new List<thing>();
        foreach (var thingGroup in thingQuery2)
        {
            if (thingGroup.Count() == 1)
            {
                foreach (thing thing in thingGroup) // there is only going to be 1
                    listOfThingsFound.Add(thing);
            }
        }

        // try position
        IEnumerable<IGrouping<string, thing>> thingQuery3 = from t in listOfThings
                                                            group t by t.Position;

        foreach (var thingGroup in thingQuery3)
        {
            if (thingGroup.Count() == 1)
            {
                foreach (thing thing in thingGroup) // there is only going to be 1
                    listOfThingsFound.Add(thing);
            }
        }
        return listOfThingsFound;
    }

http://www.programgood.net/2010/11/06/FindingUniquenessInData.aspx

上的可下载代码

3 个答案:

答案 0 :(得分:1)

我认为如果你抽象出FindUnique操作,你可以更轻松地编写测试:

static IEnumerable<T> FindDistinct<T, TKey>(this IEnumerable<T> source,
                                            Func<T, TKey> keySelector)
{
    return from item in source
           group item by keySelector(item) into grp
           where grp.Count() == 1
           from single in grp
           select single;
}

然后你可以写:

var thingsWithUniqueName = listOfThings.FindDistinct(t => t.Name);
var thingsWithUniquePosition = listOfThings.FindDistinct(t => t.Position);
var thingsWithUniqueHeight = listOfThings.FindDistinct(t => t.Height);

答案 1 :(得分:0)

您想编写如下代码:

foreach var property in Thing.Properties
{
   IEnumerable<IGrouping<string, thing>> thingQuery2 = from t in listOfThings    
                                                        group t by t.property;    
    List<thing> listOfThingsFound = new List<thing>();    
    foreach (var thingGroup in thingQuery2)    
    {    
        if (thingGroup.Count() == 1)    
        {    
            foreach (thing thing in thingGroup) // there is only going to be 1    
                listOfThingsFound.Add(thing);    
        }    
    }
     ...
 }

你只能通过反思做到这一点,这是你应该远离的东西。我唯一能想到的是将属性存储在某种集合中,比如字典和迭代

答案 2 :(得分:0)

我刚注意到Gabe已经提供了我即将发布的相同答案。我以为我会发布这个只是为了强调这个答案是LINQ的一个很好的用途。 请接受Gabe的回答,而不是这个回答。做得好Gabe!

public static IEnumerable<T> WhereUniqueByKey<T, P>(
    this IEnumerable<T> @this, Func<T, P> keySelector)
{
    return @this
        .GroupBy(keySelector)
        .Where(gt => gt.Count() == 1)
        .SelectMany(gt => gt, (_, t) => t);
}

根据Gabe的回答,我的函数是一个扩展方法,需要在静态类中定义。我们的答案之间唯一真正的区别是Gabe使用了LINQ查询语法,我使用了直接的LINQ方法调用。结果是相同的,使用情况也是如此:

var thingsWithUniqueName = listOfThings.WhereUniqueByKey(t => t.Name);
var thingsWithUniquePosition = listOfThings.WhereUniqueByKey(t => t.Position);
var thingsWithUniqueHeight = listOfThings.WhereUniqueByKey(t => t.Height);