开发者

which c# collection to use instead of List<KeyValuePair<string, double>>?

开发者 https://www.devze.com 2023-04-06 06:37 出处:网络
I want to store data such as { {"apple",15} {"pear",12.5} {"", 10} {"", 0.45}

I want to store data such as

{
 {"apple",15   }
 {"pear",12.5  }
 {"", 10       }
 {"", 0.45     }
}

Data will be plotted on a bar chart (string will be the legend and double will be the value) Insert order is important. Perfs don't matter. Strings could be duplicated or empty. (values could be duplicated too)

I need to get min and max values (easily 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));

Quite boring and unreadable. Is there a cleaner way to do it ?

StringDoubleCollection data = new StringDoubleCollection();
data.add("apple",15);
data.add("",10);

double max = data.values.Max(); 
double min = data.values.Min();

if not 开发者_StackOverflow中文版how to get the max value of List<KeyValuePair<string, double>> without too much hassle

NameValueCollection looks nice but its a <string,string> I need a <string,double>


You could create a class like the following:

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 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 to you try to improve it using an operator for cases in which you want to have just the value.

// Inside X class...
public static implicit operator X(double d)
{
    return new X(d);
}

// Somewhere else...
data.Add(50.0);


To determine which data structure you really want, lets look at your usage patterns.

  • Insert order matters.
  • You don't access your items by key.
  • You want min and max.

A heap offers min or max, but doesn't preserve order. A hash based dictionary also doesn't preserve order. A List is actually a good choice for your data structure. It is available and offers excellent support.

You can prettify your code by defining classes for both the data structure and your bar data. And you can add min/max functionality to the collection. Note: I didn't 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
    }
}


Have you looked at LookUp?

The only problem is that it's immutable, so you need to be able to create your collection in one go.

As Anthony Pegram notes, it's a bit of a pain to create one. It depends on where your data is coming from. Have a look at the ToLookup method.


If it's worth it for usability (i.e. you're using awkward collections of List<KeyValuePair<string, double>> everywhere, it might just be worth it to implement StringDoubleCollection. It wouldn't be that difficult to wrap the underlying collection with the friendlier syntax you've described in your example.

And, as other comments / answers are suggesting, the Framework doesn't seem to provide a simpler solution that matches all of your requirements...

As for "max value", I assume you mean the Key-Value Pair with the greatest value. It can be retrieved like so:

var max = list.Select(kvp => kvp.Value).Max();


Just define your own model class to hold the data instead of depending on a KeyValuePair and everything becomes 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...
    }
}


What about implementing the StringDoubleCollection to work like 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));
    }
}


You can implementing Dictionary<key, value>

   Dictionary<string, string> openWith = new Dictionary<string, string>();


   openWith.Add("txt", "notepad.exe");
   openWith.Add("bmp", "paint.exe");
   openWith.Add("dib", "paint.exe");
   openWith.Add("rtf", "wordpad.exe");

https://learn.microsoft.com/pt-br/dotnet/api/system.collections.generic.dictionary-2?view=net-5.0

0

精彩评论

暂无评论...
验证码 换一张
取 消