Hassan Brate
Hassan Brate

Reputation: 13

Sort list by a price, calculated by substrings from item inside list c#

I have a list that looks like this:

      Apple - 67 $ - 345 PIECES - 19:03
      Banana - 45 $ - 341 PIECES - 12:02
      Monkey - 34 $ - 634 PIECES - 16:01

And I want to order that list by the result of (money * amount) ordered, sort of "highest order ranking"

 finalResultOfTradeFiltering = finalResultOfTradeFiltering.OrderBy(x => Convert.ToDecimal(FindTextBetween(x,"-","$").Replace(" ", String.Empty)) * Convert.ToInt32(FindTextBetween(x, "-", "PIECES").Replace(" ", String.Empty))).ToList();

public string FindTextBetween(string text, string left, string right)
        {
            // TODO: Validate input arguments

            int beginIndex = text.IndexOf(left); // find occurence of left delimiter
            if (beginIndex == -1)
                return string.Empty; // or throw exception?

            beginIndex += left.Length;

            int endIndex = text.IndexOf(right, beginIndex); // find occurence of right delimiter
            if (endIndex == -1)
                return string.Empty; // or throw exception?

            return text.Substring(beginIndex, endIndex - beginIndex).Trim();
        }

However my code keeps crashing stating that the format is incorrect

Any clue anyone?

Upvotes: 1

Views: 66

Answers (2)

Joel Coehoorn
Joel Coehoorn

Reputation: 415735

First do this:

public class Trade
{
    public string Product {get;set;}
    public decimal Price {get;set;}
    public int Quantity {get;set;}
    public string Time {get;set;} //Make this a DateTime or new TimeOnly later
    public string OriginalLine {get;set;}

    public static Trade Parse(string input)
    {
        var result = new Trade();
        result.OriginalLine = input;

        //example line
        //Apple - 67 $ - 345 PIECES - 19:03
        var exp = new RegEx(@" - (\d+) [$] - (\d+) PIECES - (\d{1,2}:\d{2})");
        var groups = exp.Match(input).Groups;

        result.Price = Convert.ToDecimal(groups[1].Value);
        result.Quantity = Convert.ToInt32(groups[2].Value);
        result.Time = groups[3].Value;

        int EndMarker = input.IndexOf(" - ");
        result.Product = input.SubString(0, EndMarker).Trim();
        return result;
    }
}

Then use the type like so:

var result = finalResultOfTradeFiltering.
    Select(t => Trade.Parse(t)).
    OrderByDescending(t => t.Price * t.Quantity).
    Select(t => t.OriginalLine);

Note the lack of a ToList() call. Sticking with IEnumerable as much as possible, rather than converting to a List again after each step, will save on RAM and sometimes CPU, making the code much faster and more efficient. Don't convert to a List until you really need to, which is likely much later than you would think.

Even better if you are able to convert the strings to objects much earlier in your process, and not return them back to strings until after all the other processing is finished.

Upvotes: 1

The fourth bird
The fourth bird

Reputation: 163287

You might use a pattern to get capture the digits and then do the calculation using Sort.

(\d+) \$ - (\d+) PIECES
  • (\d+) \$ Capture group 1 for the money, match 1+ digits, a space and $
  • - Match literally
  • (\d+) PIECES Capture group 2 for the amount, match 1+ digits and PIECES

Assuming the pattern matches for all the given strings:

List<string> finalResultOfTradeFiltering = new List<string>() {
     "Apple - 67 $ - 345 PIECES - 19:03",
     "Banana - 45 $ - 341 PIECES - 12:02",
     "Monkey - 34 $ - 634 PIECES - 16:01"
};
var regex = @"(\d+) \$ - (\d+) PIECES";
finalResultOfTradeFiltering.Sort((a, b) => {
    var matchA = Regex.Match(a, regex);
    var matchB = Regex.Match(b, regex);
    var valueA = int.Parse(matchA.Groups[1].Value) * int.Parse(matchA.Groups[2].Value);
    var valueB = int.Parse(matchB.Groups[1].Value) * int.Parse(matchB.Groups[2].Value);
    return valueB.CompareTo(valueA);
});

finalResultOfTradeFiltering.ForEach(s => Console.WriteLine(s));

Output

Apple - 67 $ - 345 PIECES - 19:03
Monkey - 34 $ - 634 PIECES - 16:01
Banana - 45 $ - 341 PIECES - 12:02

Upvotes: 0

Related Questions