Reputation: 247
The following method print this:
Minimum Temperature is 16
Maximum Temperature is 27
The Average Temperature is 22
Now I want in addition to temperatures I also have the days in which the temperatures was maximum and minimum like:
Minimum Temperature is 16 on Day 6
Maximum Temperature is 27 on Day 8
The Average Temperature is 22
Here is the method which inserts Day and Temperature as dictionary parameters into an array and pass them to a method which determines the min,max, average.
the min and max are int values of the dictionary ,my question is that how we can determine the related string day based on these values?
// 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);
}
Upvotes: 0
Views: 2056
Reputation: 22876
Here is my attempt to make it easier. In the beginning of the file:
using KVP = System.Collections.Generic.KeyValuePair<string, int>;
and then ( or just replace all "KVP
" with "KeyValuePair<string, int>
" ) :
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"
Seems like Dictionary<string, int[]>
(array of temperatures for each day) would be more appropriate in your case, but I used array of key-value pairs to simplify the example.
ILookup<int, string>
is similar to Dictionary<int, string[]>
where each key (temperature) has multiple values (days).
Upvotes: 1
Reputation: 9463
You are facing this problem because your data structure is inadequate for the job. A Dictionary<string, int>[]
will not cut it. So please bear with me and read this long answer ...
Introduce your own classes to group properties together. The class Measurement
contains the data.
// single data point
public class Measurement {
public string Day { get; set; }
public int Temperature { get; set; }
}
Classes can also encapsulate calculations. The outside only consumes the results, so you can change the underlying implementation. Importantly, this will make your code easier to understand.
The class Month
hides the calculations. Calculations are implemented using an ICollection<Measurement>
and 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); } }
}
Take a close look at LINQ, this will save you a lot of time writing for
loops. Sorting with Orderby()
can be extended by implementing IComparable.
This console program shows how to use these classes. It creates the month "January"
, looks it up by its name and performs the calculations.
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);
}
}
}
Full example: .Net Fiddle
Upvotes: 3
Reputation: 24671
You can do this using 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();
Keep in mind that if you have multiple keys that contain the same value, you might have some issues with collisions. In this case, you can simply replace the FirstOrDefault()
with ToArray()
to get an array of keys with values that match the given value.
Upvotes: -1