As is generally the case, there are any number of ways you can go about this.
First, your sorting code above (the OrderByDescending
call). It does what you appear to want, more or less, in that it produces an ordered sequence of KeyValuePair<string, Stock>
that you can then choose from. Personally I'd just have sorted StockData.Values
to avoid all that .Value
indirection. Once sorted you can take the top performer as you're doing, or use the .Take()
method to grab the top n
items:
var byPerformance = StockData.Values.OrderByDescending(s => s.Profit * s.Volume);
var topPerformer = byPerformance.First();
var top10 = byPerformance.Take(10).ToArray();
If you want to filter by a particular performance value or range then it helps to pre-calculate the number and do your filtering on that. Either store (or calculate) the Performance
value in the class, calculate it in the class with a computed property, or tag the Stock
records with a calculated performance using an intermediate type:
- Store in the class
public class Stock {
// marking these 'init' makes them read-only after creation
public string StockSymbol { get; init; }
public double Profit { get; init; }
public int Volume { get; init; }
public double Performance { get; init; }
public Stock(string symbol, double profit, int volume)
{
StockSymbol = symbol;
Profit = profit;
Volume = volume;
Performance = profit * volume;
}
}
- Calculate in class
public class Stock
{
public string StockSymbol { get; set; }
public double Profit { get; set; }
public int Volume { get; set; }
public double Performance => Profit * Volume;
// you know what the constructor looks like
}
- Intermediate Type (with range filtering)
// let's look for those million-dollar items
var minPerformance = 1000000d;
var highPerformance = StockData.Values
// create a stream of intermediate types with the performance
.Select(s => new { Performance = s.Profit * s.Volume, Stock = s })
// sort them
.OrderByDescending(i => i.Performance)
// filter by our criteria
.Where(i => i.Performance >= minPerformance)
// pull out the stocks themselves
.Select(i => i.Value)
// and fix into an array so we don't have to do this repeatedly
.ToArray();
Ultimately though you'll probably end up looking for ways to store the data between runs, update the values and so forth. I strongly suggest looking at starting with a database and learning how to do things there. It's basically the same, you just end up with a lot more flexibility in the way you handle the data. The code to do the actual queries looks basically the same.
Once you have the data in your program, there are very few limits on how you can manipulate it. Anything you can do in Excel with the data, you can do in C#. Usually easily, sometimes with a little work.
LINQ (Language-Integrated Native Query) makes a lot of those manipulations trivial, with extensions for all sorts of things. You can take the average performance (with .Average()
) and then filter on those that perform 10% above it with some simple math. If the data follows some sort of Normal Distribution you can add your own extension (or use this one) to figure out the standard deviation... and now we're doing statistics!
The basic concepts of LINQ, and the database languages it was roughly based on, give you plenty of expressive power. And Stack Overflow is full of people who can help you figure out how to get there.