binh nguyen
binh nguyen

Reputation: 127

C# Order by List item with group

I have a List contains some BW objects with 2 properties are shape and quantity.

Depend on the preShape value and preQuantity value has been given, I will sort by each item in List<BW> with the preShape and preQuantity. The shape is priority first then the quantity is second priority. I have sorted the List<BW> with GroupBy then sort by the shape and quantity depends on the preShape and preQuantity. The result is fine like this:

 

| shape | quantity|
--------|----------
| MN22  | 20      |
| MN22  | 14      |
| MN11  | 20      |
| MN11  | 10      |
| ANT   | 20      |
| ANT   | 18      |
| ANT   | 16      |
| ANT   | 10      |

But I would like to have List<BW> like this:

| shape | quantity|
--------|----------
| MN22 | 20       |
| MN22 | 14       |
| MN11 | 10       |
| MN11 | 20       |
| ANT  | 20       |
| ANT  | 10       |
| ANT  | 16       |
| ANT  | 18       |

I tried to use for loop and swap function for to sort but the result is not like what I'm looking for.

I would like to sort by the List with the result like the 2nd table.

I need to group shape to make them in a group and I will compare shape of each item in List with the pre-shape, if they are match I will sort List with pre-shape then the quantity will be the second condition. But the quantity of the last item in group A must be followed by the same quantity of the first item in group B. If they are not match then the quantity of the first item in group B will be sorted ASC.

I attach my code here for more description my dottnetfiddle code

public static void Main()
{
    List<BW> lst = new List<BW>(){
        new BW(){ shape = "MN11", quantity = 20},
        new BW(){ shape = "MN11", quantity = 10},
        new BW(){ shape = "MN22", quantity = 14},
        new BW(){ shape = "MN22", quantity = 20},
        new BW(){ shape = "ANT", quantity = 16},
        new BW(){ shape = "ANT", quantity = 18},
        new BW(){ shape = "ANT", quantity = 20},
        new BW(){ shape = "ANT", quantity = 10}

    };
    string preShape = "MN22";
    int preQuantity = 20;

    var tempList = lst.GroupBy(c=>c.shape).Select(g=> new {shapeGroup = g.Key, BW = g.OrderBy(c=> c.shape.Equals(preShape)).ThenByDescending(c=>c.quantity)}).OrderByDescending(g=>g.shapeGroup.Equals(preShape));
    //var tempList = lst.GroupBy(c=>c.shape).Select(g=> new {shapeGroup = g.Key, BW = g.OrderByDescending(c => c.shape.Equals(preShape))}).OrderBy(g=>g.BW.First().quantity == preQuantity);;

    foreach (var shape in tempList)
    {
        var lastGroupBW_Item = shape.BW.LastOrDefault();
        //Console.WriteLine("{0}", shape.shape);
        foreach (var bw in shape.BW)
        {
            if(shape.BW.ToList().IndexOf(bw) > 0 )
            {
                shape.BW.OrderBy(c=>c.quantity == lastGroupBW_Item.quantity).ThenBy(c=>c.quantity);
            }
            Console.WriteLine("{0}|{1}", bw.shape,bw.quantity);
        }
    }

}

The last result I would like to have is like the second table I describe above. Thanks in advance!

Upvotes: 0

Views: 301

Answers (5)

binh nguyen
binh nguyen

Reputation: 127

@tymtam's solution is the correct answer for my post. Thanks everyone for the help, I have learnt more trick to use lambda to sort by my list.

Upvotes: 0

tmaj
tmaj

Reputation: 35105

I think this follows the specification.

// Order by shape first; the everybody gets it part
var shapeSorted = lst
    .OrderBy(bw => bw.shape != preShape)
    .ThenByDescending(bw => bw.shape);

// Order gropus by ascending, but if equal to last item in the previous group then first
var currentSpecialQ = preQuantity;
var r = new List<BW>();
foreach(var group in shapeSorted.GroupBy(bw => bw.shape) ) {
  r.AddRange(group.OrderBy(bw => bw.quantity != currentSpecialQ).ThenBy(bw => bw.quantity));
  currentSpecialQ = r.Last().quantity;
}

Test

Output

MN22, 20
MN22, 14
MN11, 10
MN11, 20
ANT, 20
ANT, 10
ANT, 16
ANT, 18

Code

public class BW
{
    public string shape { get; set; }
    public int quantity { get; set; }
}
class Program
{
    public static void Main(string[] args)
    {
        List<BW> lst = new List<BW>(){
            new BW(){ shape = "MN11", quantity = 20},
            new BW(){ shape = "MN11", quantity = 10},
            new BW(){ shape = "MN22", quantity = 14},
            new BW(){ shape = "MN22", quantity = 20},
            new BW(){ shape = "ANT", quantity = 16},
            new BW(){ shape = "ANT", quantity = 18},
            new BW(){ shape = "ANT", quantity = 20},
            new BW(){ shape = "ANT", quantity = 10}

        };

        string preShape = "MN22";
        int preQuantity = 20;

        // Order by shape first; the everybody gets it part
        var shapeSorted = lst
            .OrderBy(bw => bw.shape != preShape)
            .ThenByDescending(bw => bw.shape);

        // Order gropus by ascending, but if equal to last item in the previous group then first
        var currentSpecialQ = preQuantity;
        var r = new List<BW>();
        foreach(var group in shapeSorted.GroupBy(bw => bw.shape) ) {
          r.AddRange(group.OrderBy(bw => bw.quantity != currentSpecialQ).ThenBy(bw => bw.quantity));
          currentSpecialQ = r.Last().quantity;
        }

        foreach(var bw in r ) Console.WriteLine($"{bw.shape}, {bw.quantity}");

    }
}

Upvotes: 2

Hua Van Be
Hua Van Be

Reputation: 1

string preShape = "MN22";
int preQuantity = 20;

He wants the first value of group MN22 == preQuantity the first value of group MN11 nearest the last of group MN22 and the first value of group ANT nearest the last of group MN11

Example:

| MN22 | 14       |
| MN22 | 20       |
| MN11 | 10       |
| MN11 | 20       |
| ANT  | 10       |
| ANT  | 16       |
| ANT  | 18       |
| ANT  | 20       |

==>

| MN22 | 20       |
| MN22 | 14       |
| MN11 | 10       |
| MN11 | 20       |
| ANT  | 20       |
| ANT  | 18       |
| ANT  | 16       |
| ANT  | 10       |

Upvotes: -1

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186813

So items with shape == preShape should be on the top as well as quantity == preQuantity; you can sort by bool for this (note, that false < true):

 List<BW> lst = ...

 var result = lst
   .OrderByDescending(item => item.shape != preShape)       // preShape on the top  
   .ThenByDescending(item => item.shape)                    // in case of tie by shape
   .ThenByDescending(item => item.quantity != preQuantity)  // preQuantity on the top
   .ThenBy(item => item.quantity);                          // in case of tie by quantity

Demo: (I've used Tuple in order to emulate BW)

  List<(string shape, int quantity)> lst = new List<(string shape, int quantity)>(){
    ( shape :"MN11", quantity : 20),
    ( shape :"MN11", quantity : 10),
    ( shape :"MN22", quantity : 14),
    ( shape :"MN22", quantity : 20),
    ( shape : "ANT", quantity : 16),
    ( shape : "ANT", quantity : 18),
    ( shape : "ANT", quantity : 20),
    ( shape : "ANT", quantity : 10),
  };

  string preShape = "MN22";
  int preQuantity = 20;

  var result = lst
   .OrderByDescending(item => item.shape == preShape)       // preShape on the top  
   .ThenByDescending(item => item.shape)                    // in case of tie by shape
   .ThenByDescending(item => item.quantity == preQuantity)  // preQuantity on the top
   .ThenBy(item => item.quantity);                          // in case of tie by quantity

  Console.Write(string.Join(Environment.NewLine, result));

Outcome:

(MN22, 20) // preShape is the first to come; preQuantity is on the top within MN22 shape
(MN22, 14)
(MN11, 20) // preQuantity is on the top within the MIN11 shape
(MN11, 10)
(ANT, 20)  // preQuantity is on the top within the ANT shape
(ANT, 10)
(ANT, 16)
(ANT, 18)

Upvotes: 7

Saif
Saif

Reputation: 2689

Use linq to order by shape then by quantity

var tempList = lst.OrderByDescending(x => x.shape).ThenByDescending(q => q.quantity).ToList();
foreach (var b in tempList)
{
  Console.WriteLine("{0}|{1}", b.shape,b.quantity);
}

working example here

Upvotes: 1

Related Questions