Home > Blockchain >  List of numbers lowest value first, and then by input date
List of numbers lowest value first, and then by input date

Time:09-17

So I have a list of prices from a database. I would like to sort it so that the first entry in a list is the entry with the lowest number. And then all other entry are order by input date. How can this be done?

This is my code, which is a mess, sorry I'm trying stuff :)

            var itemPriceDate = itemPrice.OrderBy(d => d.Invoice.DateInvoice).ToList();
            var itemPriceDateLow= itemPriceDate.OrderBy(c => c.qtPrice).ThenBy(d => d.Invoice.DateInvoice);
            ViewBag.ItemPrice = itemPriceDateLow; ```

CodePudding user response:

LINQ is great when it works, but it sometimes does unexpected things. Depending on how large your dataset is, you may be better off doing it as a stored procedure that returns the data already ordered.

If the dataset is small or you're cornered into using C# to do it there is the option of using a custom sort function. Without knowing the exact structure of your data, this is more intended as a blanket example that will need tweaking accordingly.

Let's say your list is stored in the itemPrice variable, if you do something along the lines of:

itemPrice.Sort((a, b) => {
                  int retVal = a.qtPrice < b.qtPrice;
                  return ret != 0 ? ret : a.Invoice.DateInvoice < b.Invoice.DateInvoice;
              });

Will sort by qtPrice and then fall back to the DateInvoice field; you may need to swap the less than to a greater than to get your desired order.

CodePudding user response:

One sort is enough. What I think it should be is:

var itemPriceDateLow= itemPriceDate.OrderBy(c => c.qtPrice).ThenBy(d => d.Invoice.DateInvoice);

This will obviously give you whole collection. You might want to use .First() if you want to get top most element.

One thing to remember - ThenBy, OrderBy are ascending by default.

Take a look at this example:

class Program
{

    static void Main(string[] args)
    {
        List<ItemPrice> items = new List<ItemPrice>();
        items.Add(new ItemPrice() { Date = DateTime.Now, QtyPrice = 1});
        items.Add(new ItemPrice() { Date = DateTime.Now.AddDays(-1), QtyPrice = 1});
        items.Add(new ItemPrice() { Date = DateTime.Now, QtyPrice = 2});

        var sortedItem = items.OrderBy(p => p.QtyPrice).ThenBy(p => p.Date).First();
        Console.WriteLine($"Default Ascending sort {sortedItem.Date}, {sortedItem.QtyPrice}");

        var sortedItemWithReverseDate = items.OrderBy(p => p.QtyPrice).ThenByDescending(p => p.Date).First();
        Console.WriteLine($"Descending sort on date {sortedItemWithReverseDate.Date}, {sortedItemWithReverseDate.QtyPrice}");
    }
}

class ItemPrice {
    public DateTime Date { get; set; }
    public decimal QtyPrice { get; set; }
}

It will give you:

Default Ascending sort 16/08/2021 12:47:34, 1 Descending sort on date 17/08/2021 12:47:34, 1

CodePudding user response:

First find out the lowest value from the List(itemPrice).

double lowest_price = itemPrice.Min(c => c.qtPrice);

Next, remove the lowest element from the list.

var itemToRemove = itemPrice.Single(c => c.qtPrice == lowest_price);
itemPrice.Remove(itemToRemove);

Next, sort the remaining list based on input Date.

var newList = itemPrice.OrderByDescending(d => d.Invoice.DateInvoice).ToList();

Finally, add lowest element at first index

newList.Insert(0, lowest_price);

CodePudding user response:

You would need to iterate the collection twice in this case, since you would first need to know the Aggregate Value (Min). Then, you could use a Custom Comparer as the following.

public class CustomComparer : IComparer<Item> 
{
    private int _minValue;
    public CustomComparer(int minValue)
    {
        _minValue= minValue;
    }

    public int Compare(Item instanceA, Item instanceB)
    {
        if(instanceA.Price == _minValue) return -1;
        if(instanceB.Price == _minValue) return 1;
        return instanceA.InputDate.CompareTo(instanceB.InputDate);
    }
}

Now you can fetch the result as

var min = list.Min(x=>x.Price);
var result = list.OrderBy(x=>x,new CustomComparer(min));

Example,

public class Item
{
    public int Price{get;set;}
    public DateTime InputDate{get;set;}
}
var list = new List<Item>
{
        
        new Item{Price = 2,  InputDate=new DateTime(2021,3,1)},
        new Item{Price = 12, InputDate=new DateTime(2021,7,1)},
        new Item{Price = 12, InputDate=new DateTime(2021,9,1)},
        new Item{Price = 42, InputDate=new DateTime(2021,1,1)},
        new Item{Price = 32, InputDate=new DateTime(2021,6,1)},
        new Item{Price = 22, InputDate=new DateTime(2021,4,1)},
        new Item{Price = 2,  InputDate=new DateTime(2021,3,2)},
        new Item{Price = 12, InputDate=new DateTime(2021,2,1)}
};
    
var min = list.Min(x=>x.Price);
var result = list.OrderBy(x=>x,new CustomComparer(min));

Output

enter image description here

CodePudding user response:

Thx for all your inputs.

For me the right way to go was.

Order my "itemPrice" list by "OrderByDescending(by date)"

Then find out the lowest value from the List(itemPrice).

double lowest_price = itemPrice.Min(c => c.qtPrice);

Then declare a new List

List<qtInvoice> newItemPrice = new List<qtInvoice>();

First loop that adds all the "lowest_price" to "newItemPrice" list

foreach (var item in itemPriceDate)
            {
                if (item.qtPrice == lowest_price)
                {
                    newItemPrice.Add(item);
                }
            }

Then in second loop you add all the rest of the prices to "newItemPrice" list

foreach (var item in itemPriceDate)
            {
                if (item.qtPrice != lowest_price)
                {
                    newItemPrice.Add(item);
                }
            }
  • Related