0

I have a list of objects, I want to sort this list of object depending of a certain order ( that will be dynamically determined)

For the moment I was Able to sort it (Hardcoded)

 public void DynamicalSort(List<ProduitEdi> lProd,List<Affichages> Affichages)
              {

                var ordredAffichages = Affichages.Where(x => x.IsActive).OrderBy(y => y.Ordre)
                .ToList();
                    // Will return a list with string [Year,Price,Family,Brand]
                  lProd.Sort((prod1, prod2) =>
                  {
                      
               
                      int compare = String.Compare(prod1.Family, prod2.Family, StringComparison.Ordinal);

                      
                      if (compare != 0) return compare;

                      compare = String.Compare(prod1.Brand, prod2.Brand, StringComparison.Ordinal);

                      if (compare != 0) return compare;
                
                      compare = prod1.Price != null ? String.Compare(prod1.Price, prod2.Price, StringComparison.Ordinal) : 1;
                
                      if (compare != 0) return compare;
                
                      compare = prod1.Year != null ? String.Compare(prod1.Year, prod2.Year, StringComparison.Ordinal) : 1;

                      return compare;
                  });

                  
              }
        

In this result I was able to sort it Family first , Brand, Price , and Year

But now my list will be dynamically created and sorted, and I want the sort to follow the order of the list OrdredAffichages that will contain list of string.

Taieb
  • 920
  • 3
  • 16
  • 37
  • Related : https://stackoverflow.com/questions/33159266/a-replacement-for-orderby-switch-in-c-sharp – Drag and Drop Dec 06 '22 at 12:41
  • @DragandDrop It's not like this because I need to sort it by many fields, and not by only one. – Taieb Dec 06 '22 at 12:44
  • Quick proof of concept using only the related question code . https://dotnetfiddle.net/55d58O . you just need the first order to be OrderBy then the following order to be ThenBy. POC crafted on a phone, so it look dirty but you will get the idea. If you create the OrderByPropertyName and ThenOrderByPropertyName, it will be nice and readable. – Drag and Drop Dec 06 '22 at 13:05

1 Answers1

2

First, let's talk about Order By. To chain OrderBy, you need to link them using ThenBy.
The proposed the related question, covers how to map from a string/property name to a OrderBy. That's 99% of the job. Converting the code to ThenBy, can be done with simple copy past. We now just have to do it once for the first OrderBy, and chain the others with ThenBy.

1/. With a switch.

You can have a switch to order on the right property:

switch (order)
{
    case "prop1":
        ordered = ordered.ThenBy(o => o.prop1);
        break;
    case "prop2":
        ordered = ordered.ThenBy(o => o.prop2);
        break;
    case "prop3":
        ordered = ordered.ThenBy(o => o.prop3);
        break;
    case "prop4":
        ordered = ordered.ThenBy(o => o.prop4);
        break;
}

But you will have to maintain 2 of them One for OrderBy the other for ThenBy.

public static List<Foo> DynamicalSort(IEnumerable<Foo> source, IEnumerable<string> orderList)
{
    IOrderedEnumerable<Foo> ordered = source.OrderBy(o => o.ID);
    switch (orderList.First())
    {
        case "prop1":
            ordered = source.OrderBy(o => o.prop1);
            break;
        case "prop2":
            ordered = source.OrderBy(o => o.prop2);
            break;
        case "prop3":
            ordered = source.OrderBy(o => o.prop3);
            break;
        case "prop4":
            ordered = source.OrderBy(o => o.prop4);
            break;
    }

    foreach (var order in orderList.Skip(1))
        switch (order)
        {
            case "prop1":
                ordered = ordered.ThenBy(o => o.prop1);
                break;
            case "prop2":
                ordered = ordered.ThenBy(o => o.prop2);
                break;
            case "prop3":
                ordered = ordered.ThenBy(o => o.prop3);
                break;
            case "prop4":
                ordered = ordered.ThenBy(o => o.prop4);
                break;
        }
    return ordered.ToList();
}

2/. The generic way:

Extenting answer for the other question, with a Then By :

public static IOrderedEnumerable<T> OrderByPropertyName<T>(this IEnumerable<T> source, string propertyName)
{
    var property = typeof(T).GetProperty(propertyName);

    if (property == null) return (IOrderedEnumerable<T>)source; // or throw exception
    else return source.OrderBy(x => property.GetValue(x));
}
public static IOrderedEnumerable<T> ThenByPropertyName<T>(this IOrderedEnumerable<T> source, string propertyName)
{
    var property = typeof(T).GetProperty(propertyName);

    if (property == null) return source; // or throw exception
    else return source.ThenBy(x => property.GetValue(x));
}

Your final method will be a simple readable : OrderBy(firstPorperty), ThenBy(OtherProperties)

public static List<T> OrderByPropertiesNames<T>(this IEnumerable<T> source, IEnumerable<string> propertyName)
{
    // Please test Source and PropertiesList check FirstOrDefault Too.
    // First order because m lazy.
    var firstOrder = propertyName.First();
    var ordered = source.OrderByPropertyName(firstOrder);

    foreach (var otherOrder in propertyName.Skip(1))
    {
        ordered = ordered.ThenByPropertyName(otherOrder);
    }
    return ordered.ToList();
}

Demo

You can go deeper by adding an extra parameter for Ascending and Descending.

Drag and Drop
  • 2,672
  • 3
  • 25
  • 37