What C # collection to use instead of List <KeyValuePair <string, double >>?
I want to store data like
{ {"apple",15 } {"pear",12.5 } {"", 10 } {"", 0.45 } }
The data will be displayed on the histogram (the line will be a legend, and double - a value). Inserting an order is important. Performance does not matter. Rows can be duplicated or empty. (values ββmay be duplicated)
I need to get the minimum and maximum values ββ(easy if possible) to set the scale.
I use
List<KeyValuePair<string, double>> data = new List<KeyValuePair<string, double>>(); data.Add(new KeyValuePair<string,double>("",i));
Pretty boring and unreadable. Is there a cleaner way to do this?
StringDoubleCollection data = new StringDoubleCollection(); data.add("apple",15); data.add("",10); double max = data.values.Max(); double min = data.values.Min();
if not, how to get the maximum value List<KeyValuePair<string, double>>
without unnecessary hassle
NameValueCollection looks good, but its a <string,string>
I need <string,double>
Thank you
To determine which data structure you really want, let's look at your usage patterns.
- The value of the insertion order.
- You do not gain access to your items by key.
- You want min and max.
The pile offers min or max, but does not keep order. A hash-based dictionary also does not preserve order. The list is really a good choice for your data structure. It is available and offers excellent support.
You can prefix your code by specifying classes for both the data structure and the data in your bar. And you can add the min / max function to the collection. Note. I did not use the Linq Min / Max functions because they return the minimum value, not the minimum element.
public class BarGraphData { public string Legend { get; set; } public double Value { get; set; } } public class BarGraphDataCollection : List<BarGraphData> { // add necessary constructors, if any public BarGraphData Min() { BarGraphData min = null; // finds the minmum item // prefers the item with the lowest index foreach (BarGraphData item in this) { if ( min == null ) min = item; else if ( item.Value < min.Value ) min = item; } if ( min == null ) throw new InvalidOperationException("The list is empty."); return min; } public BarGraphData Max() { // similar implementation as Min } }
You can create a class as follows:
class X { public string Name { get; set; } public double Value { get; set; } // name is an optional parameter (this means it can be used only in C# 4) public X(double value, string name = "") { this.Name = name; this.Value = value; } // whatever }
And then get the maximum and minimum values ββusing LINQ with a selector:
var data = new List<X>(); data.Add(new X(35.0, "Apple")) data.Add(new X(50.0)); double max = data.Max(a => a.Value); double min = data.Min(a => a.Value);
EDIT: if the code above still seems unreadable, try improving it with the operator for cases where you want to only have a value.
// Inside X class... public static implicit operator X(double d) { return new X(d); } // Somewhere else... data.Add(50.0);
If this is for ease of use (that is, everywhere you use the awkward collections List<KeyValuePair<string, double>>
, it might be worth it to implement StringDoubleCollection
. It would not be easy to wrap the base collection with the friendly syntax that you described in your example .
And, as other comments / answers show, the Framework doesn't seem to provide a simpler solution that fits all your requirements ...
Regarding the "max value", I assume that you mean the pair Value Value Value with the highest value. It can be found like this:
var max = list.Select(kvp => kvp.Value).Max();
Just define your own model class for data storage, and not depending on KeyValuePair, and everything will become cleaner:
using System; using System.Collections.Generic; public class Fruit { public string Name {get; set;} public double Price {get; set;} } public class Program { public static void Main() { List<Fruit> _myFruit = new List<Fruit>(); _myFruit.Add(new Fruit{Name="apple", Price=15 }); _myFruit.Add(new Fruit{Name="pear", Price=12.5 }); _myFruit.Add(new Fruit{Name="", Price=10 }); _myFruit.Add(new Fruit{Name="", Price=0.45 }); // etc... } }
How to implement the StringDoubleCollection implementation the way you want ...
public class StringDoubleCollection { private List<KeyValuePair<string, double>> myValues; public List<double> values { get { return myValues.Select(keyValuePair => keyValuePair.Value).ToList(); } } public void add(string key, double value) { myValues.Add(new KeyValuePair<string,double>(key,value)); } }