简体   繁体   中英

Making a list distinct in C#

In C#, I have an object type 'A' that contains a list of key value pairs.

The key value pairs is a category string and a value string.

To instantiate object type A, I would have to do the following:

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. 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.

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:

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.

You need to select the distinct property first:

Because it's a list inside a list, you can use the SelectMany. The SelectMany will concat the results of subselections.

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>>

Check out the DistinctBy syntax in the morelinq project .

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. 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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