KeyValuePair重复键

时间:2015-11-14 10:26:31

标签: c# linq dictionary

我正在进行LINQ查询以获取数据库,年龄和日期的2个字段中的所有值。我想在图表上显示5个最高年龄数字。为此,我试图将年龄和日期存储在2个单独的列表,ageList和dateList中。

最初在比较每个List中的索引与索引的值时,与年龄和日期的关系是正确的。例如:

存储在ageList.ElementAt(0)的

年龄将是dateList.ElementAt(0)日期的正确值。

但是由于我要获得5个最高年龄数字,我需要排序年龄列表。通过这样做,我将失去两个列表之间的匹配。

我尝试将数据存储在SortedDictionary中,而不是Key为age,Value为date。问题是它不允许重复键。在我的情况下,我需要重复键,因为多个年龄可以相同,日期也可以相同。

这有什么办法吗?

我的代码尝试使用Dictionary存储。它在存储重复的密钥时会抛出异常。

//Linq query
var xChartData = from x in db.Person
                 select new { x.Age, x.Date };

SortedDictionary<double, DateTime> topAgeDict = new SortedDictionary<double, DateTime>();

//Storing in Dictionary
foreach (var x in xChartData)
{
    topAgeDict.Add(x.Age, x.Date); //Exception caused when repeated values
}

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

//store data as string for chart purposes
foreach (var x in topAgeDict)
{
    stringDict.Add(x.Key.ToString(), x.Value.ToString());  
}

List<string> ages = new List<string>();
List<string> dates = new List<string>();

//storing the dictionary key and value in List for element access.
ages = stringDict.Keys.ToList();
dates = stringDict.Values.ToList();

//to store only the top 5 results. This will be the data used in chart.
List<string> topFiveAge = new List<string>();
List<string> topFiveDate = new List<string>();

for (int x=1; x <= 5; x++)
{
    topFiveAge.Add(ages.ElementAt(ages.Count - x));
    topFiveDate.Add(dates.ElementAt(dates.Count - x));
}

//Chart
var topAgefilePath = Server.MapPath("~/Chart_Files/topAge.jpg");
            if (System.IO.File.Exists(topAgefilePath))
            {
                System.IO.File.Delete(topAgefilePath);
            }
            var ageChart = new Chart(580, 400);
            ageChart.AddTitle("Top Age");
            ageChart.AddSeries(
                chartType: "column",
                xValue: topFiveDate,
                yValues: topFiveAge
            );
            ageChart.Save(topAgefilePath); 

3 个答案:

答案 0 :(得分:2)

// top 5 oldest persons
var xChartData = (from x in db.Person
                 order by x.Age descending                 
                 select new { x.Age, x.Date })
                 .Take (5);

我认为没有理由把它分成两个List<> s

答案 1 :(得分:2)

你应该真正创建具体的类型,因为你将这种类型提供给某种类型的控件。

public class PersonAgeDateItem
{
    public string Age {get;set;} // should be an int though..
    public DateTime Date {get;set;}
}

获取数据的Lambda版本;

请注意,我在此处使用匿名object个实例,然后在Select之后执行PersonAgeDateItem。此实现不会受益于匿名对象实例,但是以对象比较的形式存在一些好处考虑因素(而不是在IEqualityComparer<T>上实现PersonAgeDateItemoverriding {{1} }和GetHashCode),如果您最终添加Object.Equals GroupBy ...或任何类似的情景......

Distinct

然后我们为var data = db.Person.Select(person => new { Age = person.Age, Date = person.Date }) .OrderByDescending(person => person.Age) .Take(5) .Select(person => new PersonAgeDateItem() { Age = person.Age, Date = person.Date }); // person.Age, being a string, could pose an issue.. like "2" coming after "19", "199", "1999".. etc etc Select初始化执行另一个xValue

yValue

答案 2 :(得分:1)

您可以使用Dictionary来保存年龄和日期列表,而不是List<Tuple<double, DateTime>>

var ageAndDate = from x in db.Person
                    select new Tuple<double, DateTime>(x.Age, x.Date);

var topFiveAgeWithdate = ageAndDate.OrderByDescending(t => t.Item1).Take(5).ToList();

List<string> topFiveAge = topFiveAgeWithdate.Select(t => t.Item1.ToString()).ToList();
List<string> topFiveDate = topFiveAgeWithdate.Select(t => t.Item2.ToShortDateString()).ToList();

可以使用Anonymous Type s

完成相同的操作
var ageAndDate = from x in persons
                    select new { x.Age, x.Date };

var topFiveAgeWithdate = ageAndDate.OrderByDescending(t => t.Age).Take(5).ToList();

List<string> topFiveAge = topFiveAgeWithdate.Select(t => t.Age.ToString()).ToList();
List<string> topFiveDate = topFiveAgeWithdate.Select(t => t.Date.ToShortDateString()).ToList();