简体   繁体   English

在C#中使列表与众不同

[英]Making a list distinct in C#

In C#, I have an object type 'A' that contains a list of key value pairs. 在C#中,我有一个对象类型'A',其中包含键值对列表。

The key value pairs is a category string and a value string. 键值对是类别字符串和值字符串。

To instantiate object type A, I would have to do the following: 要实例化对象类型A,我将必须执行以下操作:

List<KeyValuePair> keyValuePairs = new List<KeyValuePair>();
keyValuePairs.Add(new KeyValuePair<"Country", "U.S.A">());
keyValuePairs.Add(new KeyValuePair<"Name", "Mo">());
keyValuePairs.Add(new KeyValuePair<"Age", "33">());

A a = new A(keyValuePairs);

Eventually, I will have a List of A object types and I want to manipulate the list so that i only get unique values and I base it only on the country name. 最终,我将得到一个A对象类型的列表,并且我想操纵该列表,以便仅获得唯一值,并且仅基于国家/地区名称。 Therefore, I want the list to be reduced to only have ONE "Country", "USA", even if it appears more than once. 因此,我希望列表减少为仅包含一个“国家”,“美国”,即使它出现了不止一次。

I was looking into the linq Distinct, but it does not do what I want because it I can't define any parameters and because it doesn't seem to be able to catch two equivalent objects of type A. I know that I can override the "Equals" method, but it still doesn't solve the my problem, which is to render the list distinct based on ONE of the key value pairs. 我一直在研究linq Distinct,但是它并没有实现我想要的功能,因为它无法定义任何参数,并且因为它似乎无法捕获两个等效的A型对象。我知道可以覆盖“等于”方法,但是它仍然不能解决我的问题,即基于一个键值对使列表与众不同。

To expand upon Karl Anderson's suggestion of using morelinq, if you're unable to (or don't want to) link to another dll for your project, I implemented this myself awhile ago: 为了扩展卡尔·安德森(Karl Anderson)关于使用morelinq的建议,如果您无法(或不想)为您的项目链接到另一个dll,我不久前就实现了这一点:

public static IEnumerable<T> DistinctBy<T, U>(this IEnumerable<T> source, Func<T, U>selector)
{
    var contained = new Dictionary<U, bool>();
    foreach (var elem in source)
    {
        U selected = selector(elem);
        bool has;
        if (!contained.TryGetValue(selected, out has))
        {
            contained[selected] = true;
            yield return elem;
        }
    }
}

Used as follows: 用法如下:

collection.DistinctBy(elem => elem.Property);

In versions of .NET that support it, you can use a HashSet<T> instead of a Dictionary<T, Bool> , since we don't really care what the value is so much as that it has already been hashed. 在支持它的.NET版本中,可以使用HashSet<T>代替Dictionary<T, Bool> ,因为我们实际上并不关心该值有多少,因为它已经被哈希了。

You need to select the distinct property first: 您需要首先选择与众不同的属性:

Because it's a list inside a list, you can use the SelectMany. 因为它是列表中的列表,所以可以使用SelectMany。 The SelectMany will concat the results of subselections. SelectMany将合并子选择的结果。

List<A> listOfA = new List<A>();

listOfA.SelectMany(a => a.KeyValuePairs
    .Where(keyValue => keyValue.Key == "Country")
        .Select(keyValue => keyValue.Value))
            .Distinct();

This should be it. 应该是这样。 It will select all values where the key is "Country" and concat the lists. 它将选择键为“国家/地区”的所有值,并合并列表。 Final it will distinct the country's. 最终它将与国家不同。 Given that the property KeyValuePairs of the class A is at least a IEnumerable< KeyValuePair< string, string>> 假定类A的属性KeyValuePairs至少为IEnumerable <KeyValuePair <字符串,字符串>>

Check out the DistinctBy syntax in the morelinq project . morelinq项目中检查DistinctBy语法。

A a = new A(keyValuePairs);

a = a.DistinctBy(k => new { k.Key, k.Value }).ToList();
var result = keyValuePairs.GroupBy(x => x.Key)
                          .SelectMany(g => g.Key == "Country" ?  g.Distinct() : g);

You can use the groupby statement. 您可以使用groupby语句。 From here you can do all kind off cool stuf 在这里,您可以进行各种出色的工作

listOfA.GroupBy(i=>i.Value)

You can groupby the value and then sum all the keys or something other usefull 您可以将值分组,然后将所有键或其他有用的东西相加

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM