【问题标题】:How to get the Key of an item in the array of dictionary based on its value?如何根据值获取字典数组中项的键?
【发布时间】:2017-01-21 21:14:00
【问题描述】:

下面的方法打印这个:

Minimum Temperature is 16
Maximum Temperature is 27
The Average Temperature is 22 

现在,除了温度之外,我还想要温度最高和最低的日子,例如:

Minimum Temperature is 16 on Day 6
Maximum Temperature is 27 on Day 8
The Average Temperature is 22

这是将 Day 和 Temperature 作为字典参数插入到数组中并将它们传递给确定最小值、最大值、平均值的方法的方法。

最小值和最大值是字典的int值,我的问题是我们如何根据这些值确定相关的字符串日期?

 // if user select January , the January() execute:

 protected void Button1_Click(object sender, EventArgs e)
{
    // assigning Days and Temperatures to Dictionary and making array dictionary

    Dictionary<string, int>[] temperatures = new Dictionary<string, int>[10];
    temperatures[0] = new Dictionary<string, int>();
    temperatures[1] = new Dictionary<string, int>();
    temperatures[2] = new Dictionary<string, int>();
    temperatures[3] = new Dictionary<string, int>();
    temperatures[4] = new Dictionary<string, int>();
    temperatures[5] = new Dictionary<string, int>();
    temperatures[6] = new Dictionary<string, int>();
    temperatures[7] = new Dictionary<string, int>();
    temperatures[8] = new Dictionary<string, int>();
    temperatures[9] = new Dictionary<string, int>();

    temperatures[0].Add("Day1", 22);
    temperatures[1].Add("Day2", 23);
    temperatures[2].Add("Day3", 25);
    temperatures[3].Add("Day4", 26);
    temperatures[4].Add("Day5", 18);
    temperatures[5].Add("Day6", 16);
    temperatures[6].Add("Day7", 17);
    temperatures[7].Add("Day8", 27);
    temperatures[8].Add("Day9", 23);
    temperatures[9].Add("Day10", 24);
    if (DropDownList1.SelectedValue.ToString() == "January")
    {
        January(temperatures);
    }

  //the metthod which calculate min ,max and ..
 private void January(Dictionary<string, int>[] temperatures)
{
    int Minimumtemperture = 40;
    int Maximumtemperture = 0;
    int total = 0;
    int averageTemperatures = 0;
    // this foreach goes through array
    foreach (var temperture in temperatures)
    {

        // this foreach goes throuh dictionary 
        foreach (var degree in temperture)
        {                
            //assigning value of each dictionary to the monthTemp
            int MonthTemps = degree.Value;
            if (MonthTemps < Minimumtemperture)
            {
                Minimumtemperture = MonthTemps;
            }
            if (MonthTemps>Maximumtemperture)
            {
                Maximumtemperture = MonthTemps;
            }
            total = total + MonthTemps;

        }

        int totaltemperature = temperatures.Length;
        averageTemperatures = (total / totaltemperature);

    }

    // printing the result 

    Label1.Text = string.Format("Minimum Temperature is {0}<br/> Maximum Temperature is{1}<br/> The Average Temperature is{2}<br/>", Minimumtemperture, Maximumtemperture, averageTemperatures);

}

【问题讨论】:

  • 字典数组似乎有点不寻常。每个月都有单独的字典吗?
  • 可能是的,我这样做只是为了尝试数组的不同方面,我也对枚举做了同样的事情,我想知道在这种情况下哪个更好?可能从数据库中获取信息是更好的选择

标签: c# asp.net


【解决方案1】:

您正面临这个问题,因为您的数据结构不适合这项工作。 Dictionary&lt;string, int&gt;[] 不会删除它。所以请耐心等待并阅读这个长答案......

引入您自己的类以将属性组合在一起。 Measurement 类包含数据。

// single data point
public class Measurement {
    public string Day { get; set; }
    public int Temperature { get; set; }
}

类也可以封装计算。外部仅消耗结果,因此您可以更改底层实现。重要的是,这将使您的代码更易于理解。

Month 类隐藏了计算。使用ICollection&lt;Measurement&gt;LINQ 实现计算。

using System.Collections.Generic;
using System.Linq;

// groups measurements for a certain month and does calculations for this month
public class Month {

    public Month(string name) {
        Name = name;
        Measurements = new List<Measurement>();
    }

    // dictionary key
    public string Name { get; private set; }

    // note that the outside only knows we use an ICollection,
    // that we actually use a List in our implementation is hidden from them
    public ICollection<Measurement> Measurements { get; private set;}

    // to answer your original question:
    // LINQ .Min(m => m.Temperature) and .Max() would only return int
    // sorting will allow you to return the full Measurement, including the day
    // OrderBy runs in O(log(n)), see http://stackoverflow.com/q/3188693/1450855
    public Measurement MinByTemp { get { 
        return Measurements.OrderBy(m => m.Temperature).First(); 
    } }
    public Measurement MaxByTemp { get { 
        return Measurements.OrderBy(m => m.Temperature).Last(); 
    } }

   // more LINQ goodness
   // beware: all these getters cause recalculation each time they are called!
   // on the plus side, the results are always up to date
   public double Average { get { return Measurements.Average(r => r.Temperature); } }   
}

仔细查看LINQ,这将为您节省大量编写for循环的时间。使用Orderby() 进行排序可以通过实现IComparable 来扩展。

这个控制台程序展示了如何使用这些类。它创建月份"January",按名称查找它并执行计算。

public class Program {
    public static void Main() {

        // creating measurements
        var january = new Month("January");
        january.Measurements.Add(new Measurement { Day = "Day1", Temperature = 22 });
        january.Measurements.Add(new Measurement { Day = "Day2", Temperature = 25 });
        january.Measurements.Add(new Measurement { Day = "Day3", Temperature = 26 });
        january.Measurements.Add(new Measurement { Day = "Day4", Temperature = 18 });
        january.Measurements.Add(new Measurement { Day = "Day5", Temperature = 16 });
        january.Measurements.Add(new Measurement { Day = "Day6", Temperature = 17 });

        // finding months by their name
        // using a dictionary will perform this lookup in O(1)
        var months = new Dictionary<string, Month>();
        months.Add(january.Name, january);

        var selectedValue = "January"; // DropDownList1.SelectedValue.ToString();
        if (months.ContainsKey(selectedValue)) {
            var selectedMonth = months[selectedValue];

            // do calculations for the selected month
            // how the calculations are performed is encapsulated
            Measurement max = selectedMonth.MaxByTemp; // call getter only once
            string averageTemp = string.Format("{0:0.00}", selectedMonth.Average);

            // Label1.Text = string.Format(
            Console.WriteLine(selectedMonth.Name + ": Max " + max.Temperature + 
                " (on " + max.Day + ") Avg " +  averageTemp);
        }
        else {
            throw new KeyNotFoundException("Month not found: " + selectedValue);
        }
    }
}

完整示例:.Net Fiddle

【讨论】:

  • 非常感谢您的完整解释,我是编程新手,我不了解 LINQ 概念,但我应该尽快阅读,处理您的所有内容需要一点时间代码,但是堆栈流与像您这样的程序员拥有如此出色的社区真是太好了。
  • 很高兴为您提供帮助:)
【解决方案2】:

这是我试图让它变得更容易的尝试。在文件的开头:

using KVP = System.Collections.Generic.KeyValuePair<string, int>; 

然后(或将所有“KVP”替换为“KeyValuePair&lt;string, int&gt;”):

KVP[] temperatures = {
    new KVP("Day 1", 22),
    new KVP("Day 2", 23),
    new KVP("Day 2", 25),
    new KVP("Day 2", 26),
    new KVP("Day 2", 18),
    new KVP("Day 2", 16),
    new KVP("Day 2", 17),
    new KVP("Day 2", 27),
    new KVP("Day 2", 23),
    new KVP("Day 2", 24)
};

ILookup<int, string> lookup = temperatures.ToLookup(p => p.Value, p => p.Key);

//string example1 = string.Join(", ", lookup[23]);              // "Day 2, Day 2"
//string example2 = string.Join(", ", lookup[23].Distinct());   // "Day 2"

int min = lookup.Min(p => p.Key);                               // 16
int max = lookup.Max(p => p.Key);                               // 27

//var avg = lookup.Average(p => p.Key);                         // 22.0 (incorrect)
var avg = temperatures.Average(p => p.Value);                   // 22.1

var minDays = string.Join(", ", lookup[min].Distinct());        // "Day 2"
var maxDays = string.Join(", ", lookup[max].Distinct());        // "Day 2"

似乎Dictionary&lt;string, int[]&gt;(每天的温度数组)更适合您的情况,但我使用键值对数组来简化示例。

ILookup&lt;int, string&gt; 类似于Dictionary&lt;int, string[]&gt;,其中每个键(温度)都有多个值(天)。

【讨论】:

  • 谢谢,其实我觉得你的数据类型更适合这种情况。我还没有读过键值对数据类型,但是在这种情况下,它的方法和结构似乎比字典更有希望,但总的来说,我认为使用数据库和 LINQ 处理这样的对信息更好,我只是想练习一下数组和字典,它们在实际情况下可能没有任何用途
【解决方案3】:

您可以使用 LINQ 做到这一点:

var dict = new Dictionary<string, int>();
dict.Add("a", 3);
dict.Add("b", 4);
dict.Add("c", 5);
dict.Add("d", 6);

int value = 5; // or whatever
string key = dict.Where(kvp => kvp.Value == value)
                    .Select(kvp => kvp.Key)
                    .FirstOrDefault();

请记住,如果您有多个包含相同值的键,则可能会遇到一些冲突问题。在这种情况下,您可以简单地将FirstOrDefault() 替换为ToArray(),以获取值与给定值匹配的键数组。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-09
    • 1970-01-01
    • 1970-01-01
    • 2022-12-02
    • 2021-06-11
    • 1970-01-01
    • 1970-01-01
    • 2014-11-17
    相关资源
    最近更新 更多