Thomas
Thomas

Reputation: 10105

Sort C# map with value and key

Looking for a built-in way (preferable one-liner) to reproduce this Python line in C#.

sorted_weights = sorted(weights, key=lambda weight: (weight[1], weight[0]))

It sorts the map/dictionary using first the value and if there are duplicated values, it should sort using keys. (please note: both, keys and values, are integers)

I'd like to avoid writing an own function/loop (which I am capable of ;)) to achieve sorting if not needed. I'm pretty sure there is a functional programming approach in C# for this as well, isn't there?

Upvotes: 0

Views: 1273

Answers (3)

Harald Coppoolse
Harald Coppoolse

Reputation: 30474

Short answer

A one-liner:

Assuming your Weights have properties Value and Key:

var sortedWeights = weights.SortedBy(weight => weight.Value).ThenBy(weight => weight.Key);

Reusable method

Apparently your input is a sequence of similar items, and you want to sort first by one property, followed by a sort in another property.

My advice would be to create an extension method. After that you can use it as a one-liner LINQ like method. See extension methods demystified

To make it reusable, your <int, int> version calls a generic method:

public static IEnumerable<TSource> OrderBy<TSource, TSort1, TSort2>(
    this IEnumerable<TSource> source,
    Func<TSource, TSort1> sortProperty1,
    Func<TSource, TSort2> sortProperty2)
{
    return source.OrderBy(item => sortProperty1(item)
                 .ThenBy(item => sortProperty2(item);
}

Usage:

IEnumerable<Weight> weights = ...

// sort by Weight.Value then by Id:
var result = weights.OrderBy(weight => weight.Value, weight => weight.Id);

Or A dictionary, order by Weight.X then by dictionary key:

Dictionary<int, Weights> dict = ...
var result = dict.OrderBy(dictItem => dictItem.Value.X,
                          dictItem => dictItem.Key);

If you don't want to mention the second sort property, consider adding an extra extension method:

public static IEnumerable<KeyValuePair<TKey, TValue>> OrderByThenByKey<TKey, TValue, TProperty>(
    // TODO: invent a proper method name
    this IEnumerable<KeyValuePair<TKey, TValue>> source,
    Func<TValue, TProperty> propertySelector)
{
    // call the other OrderBy
    return source.OrderBy(propertySelector, keyValuePair => keyValuePair.Key);
}

Usage:

Dictionary<int, Weight> dict = ...
var result = dict.OrderByThenByKey(weight => weight.X);

Upvotes: 2

Gur Galler
Gur Galler

Reputation: 930

Assuming weights is a dictionary, you can try:

//using System.Linq;
var sortedWeights = weights.OrderBy(weight => weight.Value).ThenBy(weight => weight.Key);

Upvotes: 2

Artfunkel
Artfunkel

Reputation: 1852

I'm not 100% clear on what that Python code produces, but if it's a flat list of weight objects then this C# line does the same thing:

using System.Linq;

var sorted_weights = weights.OrderBy(weight => (weight[1], weight[0]));

Just be aware that output object is the equivalent of a Python generator. It will only be evaluated when you enumerate over it.

Upvotes: 1

Related Questions