使用哪种C#集合代替List<KeyValuePair<string, double>>?

8

我想存储诸如以下数据:

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

数据将在条形图上绘制(字符串将作为图例,双精度浮点数将是值)

插入顺序很重要。

性能不重要。

字符串可能会重复或为空。(值也可能重复)

我需要获取最小值和最大值(如果可能的话,易于设置比例尺)。

我使用

List<KeyValuePair<string, double>> data = new List<KeyValuePair<string, double>>();
data.Add(new KeyValuePair<string,double>("",i));

这样写太枯燥乏味,难以阅读。有没有更简洁的方法?

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

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

如果不想麻烦,如何获取 List<KeyValuePair<string, double>> 的最大值?

虽然 NameValueCollection 看起来不错,但它是一个 <string,string> 类型,我需要一个 <string,double> 类型。


stackoverflow没有转义一些'<', 导致我的帖子被删除了。所以我最后的评论是如何获取List<KeyValuePair<string, double>>的最大值,而NameValueCollection很好,但它是<string,string>,我需要一个<string,double>。 - frenchone
已为您修复了格式。 - Ray
你所需要的基本上是一个允许重复键的字典。根据这个问题:https://dev59.com/lHVC5IYBdhLWcg3w7Vtq,在框架中没有支持它的东西。你可能需要创建自己的泛型版本的NameValueCollection。 - Michael Edenfield
7个回答

6
您可以创建以下类来实现:

您可以创建以下类来实现:

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
}

然后使用带有选择器的LINQ获取最大值和最小值:

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);

编辑: 如果上面的代码对您来说仍然无法读取,请尝试使用运算符进行改进,以便在您只想要值的情况下使用。

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

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

抱歉,我在阅读时跳过了“重复”部分。不过已经进行了编辑 :) - as-cii
最好的做法是直接删除关于字典的部分,而不是让你的编辑来解释它。封装类是一个值得推荐的建议,所以我已经投了赞成票。 - Anthony Pegram

2

为了确定你真正想要的数据结构,让我们看一下你的使用模式。

  • 插入顺序很重要。
  • 你不通过键访问你的项。
  • 你想要最小值和最大值。

堆提供最小值最大值,但不保留顺序。基于哈希的字典也不保留顺序。列表实际上是你的数据结构的一个很好的选择。它可用并提供出色的支持。

你可以通过为数据结构和条形图数据定义类来美化你的代码。你还可以向集合添加最小/最大功能。注意:我没有使用Linq Min/Max函数,因为它们返回最小而不是最小元素

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
    }
}

1
只需定义自己的模型类来保存数据,而不是依赖于一个键值对,一切都会变得更加清晰简洁。
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...
    }
}

1

你看过LookUp了吗?

唯一的问题是它是不可变的,所以你需要一次性创建你的集合。

正如Anthony Pegram所指出的那样,创建一个有点麻烦。这取决于你的数据来自哪里。看看ToLookup方法。


1
问题在于它不能直接实例化。您需要从其他地方开始,然后才能投射到这里。他需要先有一个中介结构。 - Anthony Pegram
是的,没错。但这还取决于他的数据来自哪里(没有提供信息)。无论如何,了解这一点是值得的。 - Ray

1

如果为了可用性而值得(例如,您在各处使用笨拙的List<KeyValuePair<string, double>>集合,那么实现StringDoubleCollection可能是值得的。使用您在示例中描述的更友好的语法包装底层集合并不难。

正如其他评论/答案所建议的那样,框架似乎没有提供符合您所有要求的更简单的解决方案...

至于“最大值”,我想您指的是具有最大值的键值对。可以这样检索:

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

0

实现StringDoubleCollection以按照您的要求工作怎么样?...

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));
    }
}

-1

这个回答来得很晚,因为已经有另一个答案被接受了。而且它实际上并没有回答问题,因为原始问题是询问使用哪个集合来存储字符串键和双精度值。你的回答只针对了字符串和字符串。如果要回答旧问题,请确保回答能够解决实际问题并且提供新的价值。 - zeiddev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接