請問圖一 和 圖二 和 圖三 如果 分別各要寫成一個fuction 的話要怎麼寫?
有大大可以給小弟我一個方向嗎?
或是有一個範例
protected static Color ChangeColor(string AQI)
{
int number = 0;
if (int.TryParse(AQI, out number))
{
if (number > 301) return Color.DarkRed;
else if (number > 201) return Color.Purple;
else if (number > 151) return Color.Red;
else if (number > 101) return Color.Orange;
else if (number > 51) return Color.Yellow;
else return Color.Green;
}
return Color.Green;
}
protected static string setText(string Text)
{
int number = 0;
if (int.TryParse(Text, out number))
{
if (number >= 50) return "良好".ToString();
else if (number >= 100) return "普通".ToString();
else if (number >= 150) return "對敏感族群\n不健康 ".ToString();
else if (number >= 200) return "對所有族群\n不健康".ToString();
else if (number >= 300) return "非常不健康".ToString();
else if (number >= 400) return "危害".ToString();
}
return "良好".ToString();
protected static string setPic(string AQI)
{
int number = 0;
if (int.TryParse(AQI, out number))
{
if (number < 50) return @"D:\****g\picture\1.png"; //幸福臉
else if (number <= 100) return @"D:\****g\picture\2.png"; // 笑臉
else if (number <= 150) return @"D:\***\picture\3.png"; // 無奈臉
else if (number <= 200) return @"D:\*******picture\6.png"; // 流汗臉
else if (number <= 300) return @"D:\*****\picture\7.png"; // 哭哭臉
else if (number <= 400) return @"D:\****cture\8.png"; // 口罩臉
else if (number >= 400) return @"D:\***icture\8.png"; // 口罩臉
}
return @"D:\***\icture\1.png";
}
題目蠻有趣的,第一張圖的對照表小弟做出來了,
不過圖片下方第三點說明不是很了解,
內容提到 AQI 200 以上,這會橫跨 2 個區間,
且查了一下政府觀測站的網站,並沒有提供 SO2 24hr 的資料,這樣該如何計算呢,
這部分覺得有點困惑。
先附上對照表的程式碼:
AQI_Table_Ex
public static class AQI_Table_Ex
{
/// <summary>
/// 產生空氣品質指標對照表資料
/// </summary>
/// <returns></returns>
public static List<AQI_Table> Create()
{
var table = new List<AQI_Table>
{
new AQI_Table
{
LevelType = LevelType.L1,
AQI_low = 0,
AQI_hight = 50,
O3_8hr_low = 0.000m,
O3_8hr_hight = 0.054m,
O3_1hr_low = null,
O3_1hr_hight = null,
PM2_5_low = 0.0m,
PM2_5_hight = 15.4m,
PM10_low = 0m,
PM10_hight = 54m,
CO_8hr_low = 0m,
CO_8hr_hight = 4.4m,
SO2_1hr_low = 0m,
SO2_1hr_hight = 35m,
SO2_8hr_low = null,
SO2_8hr_hight = null,
NO2_1hr_low = 0m,
NO2_1hr_hight = 53m,
Text = "良好",
Color = Color.Green,
PicPath = "picture1.png",
},
new AQI_Table
{
LevelType = LevelType.L2,
AQI_low = 51,
AQI_hight = 100,
O3_8hr_low = 0.055m,
O3_8hr_hight = 0.070m,
O3_1hr_low = null,
O3_1hr_hight = null,
PM2_5_low = 15.5m,
PM2_5_hight = 35.4m,
PM10_low = 55m,
PM10_hight = 125m,
CO_8hr_low = 4.5m,
CO_8hr_hight = 9.4m,
SO2_1hr_low = 36m,
SO2_1hr_hight = 75m,
SO2_8hr_low = null,
SO2_8hr_hight = null,
NO2_1hr_low = 54m,
NO2_1hr_hight = 100m,
Text = "普通",
Color = Color.Yellow,
PicPath = "picture2.png",
},
new AQI_Table
{
LevelType = LevelType.L3,
AQI_low = 101,
AQI_hight = 150,
O3_8hr_low = 0.071m,
O3_8hr_hight = 0.085m,
O3_1hr_low = 0.125m,
O3_1hr_hight = 0.164m,
PM2_5_low = 35.5m,
PM2_5_hight = 54.4m,
PM10_low = 126m,
PM10_hight = 254m,
CO_8hr_low = 9.5m,
CO_8hr_hight = 12.4m,
SO2_1hr_low = 76m,
SO2_1hr_hight = 185m,
SO2_8hr_low = null,
SO2_8hr_hight = null,
NO2_1hr_low = 101m,
NO2_1hr_hight = 360m,
Text = "對敏感族群\n不健康",
Color = Color.Orange,
PicPath = "picture3.png",
},
new AQI_Table
{
LevelType = LevelType.L4,
AQI_low = 151,
AQI_hight = 200,
O3_8hr_low = 0.086m,
O3_8hr_hight = 0.105m,
O3_1hr_low = 0.165m,
O3_1hr_hight = 0.204m,
PM2_5_low = 54.5m,
PM2_5_hight = 150.4m,
PM10_low = 255m,
PM10_hight = 354m,
CO_8hr_low = 12.5m,
CO_8hr_hight = 15.4m,
SO2_1hr_low = 186m,
SO2_1hr_hight = 304m,
SO2_8hr_low = 186m,
SO2_8hr_hight = 304m,
NO2_1hr_low = 361m,
NO2_1hr_hight = 649m,
Text = "對所有族群\n不健康",
Color = Color.Red,
PicPath = "picture4.png",
},
new AQI_Table
{
LevelType = LevelType.L5,
AQI_low = 201,
AQI_hight = 300,
O3_8hr_low = 0.106m,
O3_8hr_hight = 0.200m,
O3_1hr_low = 0.205m,
O3_1hr_hight = 0.404m,
PM2_5_low = 150.5m,
PM2_5_hight = 250.4m,
PM10_low = 355m,
PM10_hight = 424m,
CO_8hr_low = 15.5m,
CO_8hr_hight = 30.4m,
SO2_1hr_low = null,
SO2_1hr_hight = null,
SO2_8hr_low = 305m,
SO2_8hr_hight = 604m,
NO2_1hr_low = 650m,
NO2_1hr_hight = 1249m,
Text = "非常不健康",
Color = Color.Purple,
PicPath = "picture5.png",
},
new AQI_Table
{
LevelType = LevelType.L6,
AQI_low = 300,
AQI_hight = 400,
O3_8hr_low = null,
O3_8hr_hight = null,
O3_1hr_low = 0.405m,
O3_1hr_hight = 0.504m,
PM2_5_low = 250.5m,
PM2_5_hight = 350.4m,
PM10_low = 425m,
PM10_hight = 504m,
CO_8hr_low = 30.5m,
CO_8hr_hight = 40.4m,
SO2_1hr_low = null,
SO2_1hr_hight = null,
SO2_8hr_low = 605m,
SO2_8hr_hight = 804m,
NO2_1hr_low = 1250m,
NO2_1hr_hight = 1649m,
Text = "危害",
Color = Color.DarkRed,
PicPath = "picture6.png",
},
new AQI_Table
{
LevelType = LevelType.L7,
AQI_low = 400,
AQI_hight = 500,
O3_8hr_low = null,
O3_8hr_hight = null,
O3_1hr_low = 0.505m,
O3_1hr_hight = 0.604m,
PM2_5_low = 350.5m,
PM2_5_hight = 500.4m,
PM10_low = 505m,
PM10_hight = 604m,
CO_8hr_low = 40.5m,
CO_8hr_hight = 50.4m,
SO2_1hr_low = null,
SO2_1hr_hight = null,
SO2_8hr_low = 805m,
SO2_8hr_hight = 1004m,
NO2_1hr_low = 1650m,
NO2_1hr_hight = 2049m,
Text = "危害",
Color = Color.DarkRed,
PicPath = "picture7.png",
},
};
return table;
}
}
AQI_Table
/// <summary>
/// 空氣品質指標對照表
/// </summary>
public class AQI_Table
{
public decimal? O3_1hr_low { get; set; }
public decimal? O3_1hr_hight { get; set; }
public decimal? O3_8hr_low { get; set; }
public decimal? O3_8hr_hight { get; set; }
public decimal? SO2_1hr_low { get; set; }
public decimal? SO2_1hr_hight { get; set; }
public decimal? SO2_8hr_low { get; set; }
public decimal? SO2_8hr_hight { get; set; }
public decimal? CO_8hr_low { get; set; }
public decimal? CO_8hr_hight { get; set; }
public decimal? NO2_1hr_low { get; set; }
public decimal? NO2_1hr_hight { get; set; }
public decimal? PM2_5_low { get; set; }
public decimal? PM2_5_hight { get; set; }
public decimal? PM10_low { get; set; }
public decimal? PM10_hight { get; set; }
public int AQI_low { get; set; }
public int AQI_hight { get; set; }
public LevelType LevelType { get; set; }
public string Text { get; set; }
public Color Color { get; set; }
public string PicPath { get; set; }
}
LevelType
/// <summary>
/// AQI 等級
/// </summary>
public enum LevelType
{
L1 = 1,
L2,
L3,
L4,
L5,
L6,
L7,
}
PollutantType
/// <summary>
/// 汙染物類型
/// </summary>
public enum PollutantType
{
O3_8hr,
O3_1hr,
PM2_5,
PM10,
CO_8hr,
SO2_1hr,
SO2_8hr,
NO2_1hr
}
函數我就沒有特別寫,可以用 Linq 查表。
var table = AQI_Table_Ex.Create();
var item = table
.Where(it => it.AQI_low <= AQI && it.AQI_hight >= AQI)
.FirstOrDefault();
好晚了今天先到這裡,明天有空再繼續研究 XD。
關於計算公式,當然我寫的是有問題,我只是把構想先寫看看
private static void PM25_C(Double C25) //PM2.5 ( C ) 移動平均
{
string sq16 = @"Select TOP12 **** FROM *** WHERE **** ORDER BY M_DateTime DESC";
string sq17 = @"Select TOP4 *** FROM ***WHERE *** ORDER BY M_DateTime DESC";
DataTable dt16= SqlCommand(sq16);
DataTable dt17 = SqlCommand(sq17);
Double PM12H_Ave = dt16 / 12;
Double PM4H_Ave = dt17 / 4;
Double PM25_C = 0.5 * PM12H_Ave + 0.5 * PM4H_Ave;
dt16.Dispose();
dt17.Dispose();
}
private static void PM10_C(Double C24) //PM10 ( C ) 移動平均
{
string sq18 = @"Select TOP12 *** FROM *** ORDER BY M DESC";
string sq19 = @"Select TOP4 *** FROM *** WHERE *** ORDER BY M_DateTime DESC";
DataTable dt18 = SqlCommand(sq18);
DataTable dt19 = SqlCommand(sq19);
Double PM12H_Ave = dt18 / 12;
Double PM4H_Ave = dt19 / 4;
Double PM25_C = 0.5 * PM12H_Ave + 0.5 * PM4H_Ave;
dt18.Dispose();
dt19.Dispose();
}
//8小時移動平均值計算方式:取最近連續8小時移動平均值 (4筆有效)
private static void O38H_C(Double O3_8) // O3 8H 移動平均
{
string sq20 = @"Select TOP8 *** FROM ** WHERE ***RDER BY M_DateTime DESC";
DataTable dt20 = SqlCommand(sq20);
Double O38H_Ave = dt20 / 8;
dt20.Dispose();
}
private static void CO8H_C(Double CO_8) // CO 8H 移動平均
{
string sq21 = @"Select TOP8 *** FROM *** ORDER BY M_DateTime DESC";
DataTable dt21 = SqlCommand(sq21);
Double O38H_Ave = dt21 / 8;
dt21.Dispose();
}
//SO2 24H 移動平均值
private static void SO2_24H_C(Double SO2_24) // SO2 24H 濃度平均值
{
string sq22 = @"Select TOP24 *** FROM *** WHERE**R BY M_DateTime DESC";
DataTable dt22 = SqlCommand(sq22);
Double O38H_Ave = dt22 / 24;
dt22.Dispose();
}
裡面的前面幾小時之類移動平均之類,我是取資料庫比如Top 4,然後變
dt
在把dt / 多少 ;
當然那樣是錯的
**前4小時2筆有效,前12小時6筆有效
**4筆有效
使用布林代數 true ?
private static void All_AQI(Double I) // AQI 計算公式
{
int Ihigh = 0; // AQI 範圍數值 大 表格資料
int Ilow = 0; // AQI 範圍數值 小 表格資料
Double Chigh = 0; // PM2.5 表格 大
Double Clow = 0; // PM2.5 表格 小
Double C = 0; // 移動平均? 汙燃物 輸入值 活的
Double IAQI = ((Ihigh - Ilow) / (Chigh - Clow)) * (C - Clow) + Ilow;
}
移動平均計算方式,我和您想的差不多,查出 TOP 再去算平均。
前4小時2筆有效,前12小時6筆有效
這段話,我猜測每1小時會紀錄1筆觀測資料,
前4小時會有4筆資料,TOP 4 再 WHERE 現在時間-觀測時間<=4小時
如果資料大於等於2筆則為有效值,如果資料小於2筆 (例如監測系統故障),則移動平均因資料不足為無效值。
以上是我的猜測,不確定,哈哈哈。
最後您的 All_AQI 是計算單項 IAQI 的函數,可以利用此函數,算出各項的 IAQI 後取最大值,就是我們期望的 AQI 結果。
是的 每一小時撈一次資料庫,是阿..計算後 6項取最大值 為本整點的AQI,只是我還在想怎麼樣移動平均怎麼寫,我只寫大概,比如下面這個是錯的
Double PM12H_Ave = dt16 / 12;
Double PM4H_Ave = dt17 / 4;
謝謝大大 一值分享你的方法與交流
C# 可以這樣做,不過如果能用 SQL 更簡單。
var PM12H_Ave = dt16.AsEnumerable()
.Select(it => double.Parse(it["PM12H"].ToString()))
.Sum() / 12;
前4小時2筆有效
,有效的意義我理解正確嗎?
哈哈哈,覺得算 AQI 蠻有趣的。
前4小時2筆有效,前12小時6筆有效
應該是我取資料庫
我有一個狀態是 比如 010 , 011 之類有效,020 ,021 之類無效,其實我有一個Excel 表格
以下是我秀畫面判斷的資料
protected static string KBstatus(string status)
{
int number = 0;
if (int.TryParse(status, out number))
{
if (number == 020) return "校正中";
else if (number == 021) return "校正中";
else if (number == 026) return "校正中";
else if (number == 030) return "校正中";
else if (number == 031) return "維修中";
else if (number == 038) return "定期保養";
else if (number == 035) return "數據量不足";
}
return "校正中";
}
其中 (020,021,026,030,031,038,035) 為資料庫撈資料 狀態值,所顯示代碼..
一開始我也以為有欄位註記,不過撈資料的邏輯想不通,
假設4小時內的資料有4筆,其中3筆有效,1筆無效,
那麼我只撈3筆有效中的前2筆嗎,覺得怪怪的,哈哈哈
恩恩 對 4小時 2筆有效, 只要 其中 裡面 2筆狀態是顯示為正確狀態,就可以了
撈3筆有效中前兩筆因該是這樣
@fy 大 請問您說的這段 函式
var table = AQI_Table_Ex.Create();
var item = table
.Where(it => it.AQI_low <= AQI && it.AQI_hight >= AQI)
.FirstOrDefault();
還要多哪一些西呢?我改成
void Main()
{ var table = AQI_Table_Ex.Create();
var item = table
.Where(it => it.AQI_low <= AQI && it.AQI_hight >= AQI)
.FirstOrDefault();
}
其中AQI 沒有設定他的變數 讀不他這一個變數
恩要在最上面宣告。
var AQI = 100;
請問我的 移動平均 和AQI ,關於裡面的 return , 丟到 excel 空格裡
public double get_O3_8H_average() //O3_8H ( C ) 移動平均
{
string sq14 = @"Select TOP8 A525V FROM P1234567_Hr_2018 WHERE DP_NO = 'A009' ORDER BY M_DateTime DESC";
DataTable dt14 = SqlCommand(sq14);
//前8小時平均
var O3_8H_C = dt14.AsEnumerable()
.Select(it => double.Parse(it["O3_8H"].ToString()))
.Sum() / 12;
dt14.Dispose();
return O3_8H_C;
}
上面 我return 出來的 O3_8H_C,和I 其他地方不能使用他嗎?
我有一個地方是插入移動平均
可是卻找不到 : O3_8H_C ,請問大大 不是我上面公式 有return 出來了?
然後把移動平均和AQI和在一起是這樣嗎?
求解紅色蝌蚪
public static double AQI(Double I) // AQI 計算公式
{
int Ihigh = 0; // AQI 範圍數值 大 表格資料
int Ilow = 0; // AQI 範圍數值 小 表格資料
Double Chigh = 0; // PM2.5 表格 大
Double Clow = 0; // PM2.5 表格 小
Double C = 0; // 移動平均? 算出來數值輸入值 活的
I = ((Ihigh - Ilow) / (Chigh - Clow)) * (C - Clow) + Ilow;
return I;
}
//算好移動平均 插入AQI 計算公式
public static void Main ()
{
double average = get_PM25_average();
double AQIcal = AQI(average);
}
哈哈哈,這樣看不太出來,我試著回答看看。
O3_8H_C ,請問大大 不是我上面公式 有return 出來了
有 return,是不是外面沒有宣告變數去接函數的回傳?
函數在同一個類別內可以直接呼叫,get_PM25_average 是不是沒有宣告或不在同類別?
不好意思 請問 要如何去接函數的回傳?..
這樣~
var O3_8H_C = get_O3_8H_average();
sheet.Range["F3"].Text = O3_8H_C.ToString();
出來數值都是:19.96916667 和 21.35666666
把公式的 var 和 double 都改成int
int O3_8H_C = get_O3_8H_average();
sheet.Range["F3"].Text = O3_8H_C.ToString();
就跑個啥 字串功能不對 冏.
難道問題點 在取決於 資料庫來源 本來就屬於 小數?(double ,var) 型別
冏. 讀來源資料庫 真的都小數, 難怪 改int 說字串啥問題
可惜出來解果, 依照環保局來說 都是整數說..
謝謝大大 回復
哈哈哈,小數點正常,因為我們函數的回傳型態是 double,
var 是 推斷型別
,它不是真正的型態,編譯後 var 會以函數的回傳 double 取代。
C# 是強型別的語言,因此不能用 int 去接收 double 的值。
int O3_8H_C = get_O3_8H_average();
如果想要取整數,可以用 Round 函數先四捨五入到整數位,再轉型成 int。
var O3_8H_C = (int)Math.Round(get_O3_8H_average());
我發現 移動平均 好了之後, 再丟進 大大給的 table AQI 表
弄成 AQI 公式 好難啊...
6個狀態 丟進去
算成6個AQI (A,B,C,D,E,F)
比如A的AQI大 取他,AQI 為整點AQI值
問題是怎麼把移動平均等各項數值
丟到大您的表?
丟好之後判斷在哪一個區間,在丟到AQI 計算公式
計算公式我寫好,只是不曉得,怎麼去 餵入數值..
用 SQL + DataTable 應該會比較好處理,用 Class 要寫好長,哈哈哈
研究了一下表達式樹,雖然精簡了程式碼,不過比較難懂,給您參考看看。
/// <summary>
/// 計算 AQI
/// </summary>
public static int CalcAQI(this List<AQI_Table> airQualityTable,
decimal O3_8hr,
decimal O3_1hr,
decimal PM2_5,
decimal PM10,
decimal CO_8hr,
decimal SO2_1hr,
decimal NO2_1hr)
{
//汙染物陣列
var pollutantList = new List<Tuple<PollutantType, decimal>>
{
new Tuple<PollutantType, decimal>(
PollutantType.O3_8hr, O3_8hr),
new Tuple<PollutantType, decimal>(
PollutantType.O3_1hr, O3_1hr),
new Tuple<PollutantType, decimal>(
PollutantType.PM2_5, PM2_5),
new Tuple<PollutantType, decimal>(
PollutantType.PM10, PM10),
new Tuple<PollutantType, decimal>(
PollutantType.CO_8hr, CO_8hr),
new Tuple<PollutantType, decimal>(
PollutantType.SO2_1hr, SO2_1hr),
new Tuple<PollutantType, decimal>(
PollutantType.NO2_1hr, NO2_1hr),
};
var pollutantRowList = pollutantList.Select(it =>
{
//產生可動態取得 low、high 的表達式樹
var pollutantName = it.Item1.ToString();
var type = typeof(AQI_Table);
var itParam = Expression.Parameter(type, "it");
var lowGetter = Expression.Property(itParam,
type.GetProperty($"{pollutantName}_low"));
var highGetter = Expression.Property(itParam,
type.GetProperty($"{pollutantName}_hight"));
var getLow = Expression.Lambda<Func<AQI_Table, decimal?>>(
lowGetter, itParam).Compile();
var getHigh = Expression.Lambda<Func<AQI_Table, decimal?>>(
highGetter, itParam).Compile();
var pollutantType = it.Item1;
var C = it.Item2;
//查表
var row = airQualityTable
.Where(itt => C >= getLow(itt) && C <= getHigh(itt))
.FirstOrDefault();
//查不到回傳 null
return row == null ? null : new
{
pollutantType = pollutantType,
row = row,
C = C,
Clow = getLow(row).Value,
Chigh = getHigh(row).Value,
Ilow = row.AQI_low,
Ihigh = row.AQI_hight,
};
});
//IAQI 計算公式
var calc = (Func<decimal, decimal, decimal, int, int, int>)
((C, Clow, Chigh, Ilow, Ihigh) =>
{
return (int)Math.Ceiling(
(Ihigh - Ilow) / (Chigh - Clow) * (C - Clow) + Ilow);
});
//計算 IAQI
var IAQI = pollutantRowList.Where(it => it != null)
.Select(it => new
{
pollutantType = it.pollutantType,
IAQI = calc(it.C, it.Clow, it.Chigh, it.Ilow, it.Ihigh),
});
//算出最大值
return IAQI.Max(it => it.IAQI);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var table = AQI_Table_Ex.Create();
var AQI = table.CalcAQI(38m * 1000, 21m * 1000, 18m, 34m,
0.30m, 1.8m, 5.5m);
}
不好意思,有點看不太懂, 最後一段,大概要新增一個 Button ,其中有一段是
table.CalcAQI(38m * 1000, 21m * 1000, 18m, 34m, 0.30m, 1.8m, 5.5m, out AQI, out pollutantTypes);
請問裡面數字是?我對過表格,數字好像沒在裡面
您的意思是本來是要寫一個class,功能會有把計算好各項移動公式丟到您之前創造的Table , 去判斷他落在哪一個區間, 判斷好後丟到AQI計算公式, 然後重複6次, 然後有6個,然後在取最大,即為該整點取樣AQI數值
因為我把您code 貼有 一些 紅色蝌蚪
然後表達式樹,...
數字是算好的移動平均,函數的參數就是那七項,後面兩個 out 則會回傳我們算出來七項中的最大值,也就是 AQI,和指標汙染物。
public static int CalcAQI(this List<AQI_Table> airQualityTable,
decimal O3_8hr,
decimal O3_1hr,
decimal PM2_5,
decimal PM10,
decimal CO_8hr,
decimal SO2_1hr,
decimal NO2_1hr)
紅色蝌蚪的部分:
Button_Click 函數是我自己測試用的 (WPF專案),您取中間的程式就好。
CalcAQI 函數要宣告在 AQI_Table_Ex 類別內。
後來想想 out pollutantTypes
其實可以拉到外面做,CalcAQI 就單純的計算 AQI 就好,這樣比較單純,我修改一下。
大大我大概知道您 表達式樹 ,當最上面, 把上面之前 算好 移動平均丟到 下層 然後一層一層下去 一直到這裡
//回傳結果
AQI = max;
//指標汙染物可以有多個
pollutantTypes = IAQI
.Where(it => it.IAQI == max)
.Select(it => it.pollutantType)
.ToArray();
}
這狀況如果沒錯的話,指標汙染物為6種AQI 的最大值,取其該項的AQI,為目前AQI
然後
靜態型別關係,大概是指
public static void CalcAQI(this List<AQI_Table> airQualityTable,
上面 我改成
把
static void
刪掉,只單純 定義 public 之類,雖然上面From 靜態關係 紅色蝌蚪會消失
但是接下來This等等 之類 又有新的紅色蝌蚪
然後
public static void CalcAQI(this List<AQI_Table> airQualityTable,
decimal O3_8H_C,
decimal O3_1hr,
decimal PM25_C,
decimal PM10_C,
decimal CO_8H_C,
decimal SO2_24H_C,
decimal NO2_1hr,
out int AQI,
您這段意思是取移動平均上面return 出來後的數值,我其中變數 是改成我上面取的變數這樣.
至於後面那部分
取後面中間程式我就不曉的了..
感謝大大都一直為我解惑...
沒錯,程式邏輯如您所說。
CalcAQI 函數要放在 AQI_Table_Ex 類別內,不是把 static 拿掉 XD,
CalcAQI 有修改成比較符合你的需求,下面的數值放算出來的各項移動平均。
var table = AQI_Table_Ex.Create();
var AQI = table.CalcAQI(38m * 1000, 21m * 1000, 18m, 34m,
0.30m, 1.8m, 5.5m);
大大不好意思
六日試了很久..還是有點沒辦法
請問之前您貼的那一段函式
用 Linq 查表。 這一段還需要嗎?
var table = AQI_Table_Ex.Create();
var item = table
.Where(it => it.AQI_low <= AQI && it.AQI_hight >= AQI)
.FirstOrDefault();
然後CalcAQI 函數要放在 AQI_Table_Ex 類別內,意思是把它塞進class裡,我是連下面都塞進去了,然後再把
var table = AQI_Table_Ex.Create();
var AQI = table.CalcAQI(38m * 1000, 21m * 1000, 18m, 34m,
0.30m, 1.8m, 5.5m);
這一段也塞進去了
天啊~好多蝌蚪阿
public static class AQI_Table_Ex
{
/// <summary>
/// 產生空氣品質指標對照表資料
/// </summary>
/// <returns></returns>
public static List<AQI_Table> Create()
{
var table = new List<AQI_Table>();
{
// | Level | AQI | O3 8hr | O3 1hr | PM2.5 | PM10 | CO | SO2 1hr | SO2 8hr | NO2 |
new AQI_Table(LevelType.L1, 0, 50, 0.000m, 0.054m, null, null, 0.0m, 15.4m, 0m, 54m, 0m, 4.4m, 0m, 35m, null, null, 0m, 53m, "良好", Color.Green, @"D:\DocToImg\picture\1.png");
new AQI_Table(LevelType.L2, 51, 100, 0.055m, 0.070m, null, null, 15.5m, 35.4m, 55m, 125m, 4.5m, 9.4m, 36m, 75m, null, null, 54m, 100m, "普通", Color.Yellow, @"D:\DocToImg\picture\2.png");
new AQI_Table(LevelType.L3, 101, 150, 0.071m, 0.085m, 0.125m, 0.164m, 35.5m, 54.4m, 126m, 254m, 9.5m, 12.4m, 76m, 185m, null, null, 101m, 360m, "對敏感族群\n不健康", Color.Orange, @"D:\DocToImg\picture\3.png");
new AQI_Table(LevelType.L4, 151, 200, 0.086m, 0.105m, 0.165m, 0.204m, 54.5m, 150.4m, 255m, 354m, 12.5m, 15.4m, 186m, 304m, 186m, 304m, 361m, 649m, "對所有族群\n不健康", Color.Red, @"D:\DocToImg\picture\4.png");
new AQI_Table(LevelType.L5, 201, 300, 0.106m, 0.200m, 0.205m, 0.404m, 150.5m, 250.4m, 355m, 424m, 15.5m, 30.4m, null, null, 305m, 604m, 650m, 1249m, "非常不健康", Color.Purple, @"D:\DocToImg\picture\5.png");
new AQI_Table(LevelType.L6, 300, 400, null, null, 0.405m, 0.504m, 250.5m, 350.4m, 425m, 504m, 30.5m, 40.4m, null, null, 605m, 804m, 1250m, 1649m, "危害", Color.DarkRed, @"D:\DocToImg\picture\6.png");
new AQI_Table(LevelType.L7, 400, 500, null, null, 0.505m, 0.604m, 350.5m, 500.4m, 505m, 604m, 40.5m, 50.4m, null, null, 805m, 1004m, 1650m, 2049m, "危害", Color.DarkRed, @"D:\DocToImg\picture\7.png");
}
return table;
}
public static void CalcAQI(this List<AQI_Table> airQualityTable,
decimal O3_8H_C,
decimal O3_1hr,
decimal PM25_C,
decimal PM10_C,
decimal CO_8H_C,
decimal SO2_24H_C,
decimal NO2_1hr,
out int AQI,
out PollutantType[] pollutantTypes)
{
//汙染物陣列
var pollutantList = new List<Tuple<PollutantType, decimal>>
{
new Tuple<PollutantType, decimal>(
PollutantType.O3_8hr, O3_8H_C),
new Tuple<PollutantType, decimal>(
PollutantType.O3_1hr, O3_1hr),
new Tuple<PollutantType, decimal>(
PollutantType.PM2_5, PM25_C),
new Tuple<PollutantType, decimal>(
PollutantType.PM10, PM10_C),
new Tuple<PollutantType, decimal>(
PollutantType.CO_8hr, CO_8H_C),
new Tuple<PollutantType, decimal>(
PollutantType.SO2_1hr, SO2_24H_C),
new Tuple<PollutantType, decimal>(
PollutantType.NO2_1hr, NO2_1hr),
};
var pollutantRowList = pollutantList.Select(it =>
{
//產生可動態取得 low、high 的表達式樹
var pollutantName = it.Item1.ToString();
var type = typeof(AQI_Table);
var itParam = Expression.Parameter(type, "it");
var lowGetter = Expression.Property(itParam,
type.GetProperty($"{pollutantName}_low"));
var highGetter = Expression.Property(itParam,
type.GetProperty($"{pollutantName}_hight"));
var getLow = Expression.Lambda<Func<AQI_Table, decimal?>>(
lowGetter, itParam).Compile();
var getHigh = Expression.Lambda<Func<AQI_Table, decimal?>>(
highGetter, itParam).Compile();
var pollutantType = it.Item1;
var C = it.Item2;
//查表
var row = airQualityTable
.Where(itt => C >= getLow(itt) && C <= getHigh(itt))
.FirstOrDefault();
//查不到回傳 null
return row == null ? null : new
{
pollutantType = pollutantType,
row = row,
C = C,
Clow = getLow(row).Value,
Chigh = getHigh(row).Value,
Ilow = row.AQI_low,
Ihigh = row.AQI_hight,
};
});
//IAQI 計算公式
var calc = (Func<decimal, decimal, decimal, int, int, int>)
((C, Clow, Chigh, Ilow, Ihigh) =>
{
return (int)Math.Ceiling(
(Ihigh - Ilow) / (Chigh - Clow) * (C - Clow) + Ilow);
});
//計算 IAQI
var IAQI = pollutantRowList.Where(it => it != null)
.Select(it => new
{
pollutantType = it.pollutantType,
IAQI = calc(it.C, it.Clow, it.Chigh, it.Ilow, it.Ihigh),
})
.ToList();
//算出最大值
var max = IAQI.Max(it => it.IAQI);
//回傳結果
AQI = max;
//指標汙染物可以有多個
pollutantTypes = IAQI
.Where(it => it.IAQI == max)
.Select(it => it.pollutantType)
.ToArray();
}
}
public static void AQI()
{
var O3_8H_C = get_O3_8H_average();
var CO_8H_C = get_CO_8H_average();
int PM25_24H_C = get_PM25_average();
var PM10_24H_C = get_PM10_average();
var pollutantTypes = null as PollutantType[];
var table = AQI_Table_Ex.Create();
var AQI = table.CalcAQI(38m * 1000, 21m * 1000, 18m, 34m, 0.30m, 1.8m,
5.5m);
return AQI;
}
}
大大可以幫我Help嗎.
後面您之前說的那一段 塞移動平均這段,因為是把算出來後的移動平均數值塞進去,畢竟是活的
下面我新增一些code
當然蝌蚪部分還是如上圖所示
public static double AQI()
{
string sq1 = @"SELECT TOP 1 *** FROM ** WHERE *** ORDER BY M_DateTime DESC "; //O3臭氧 小時濃度
string sq2 = @"SELECT TOP 1 *** FROM *** WHERE **** ORDER BY M_DateTime DESC "; //SO2 小時濃度
string sq3 = @"SELECT TOP 1 **** FROM *** WHERE **** ORDER BY M_DateTime DESC "; //NO2 小時濃度
DataTable dt = SqlCommand(sq1);
DataTable dt2 = SqlCommand(sq2);
DataTable dt3 = SqlCommand(sq3);
var O3_8H_C = get_O3_8H_average();
var CO_8H_C = get_CO_8H_average();
int PM25_24H_C = get_PM25_average();
var PM10_24H_C = get_PM10_average();
var pollutantTypes = null as PollutantType[];
var table = AQI_Table_Ex.Create();
var AQI = table.CalcAQI(dt, dt2, dt3, CO_8H_C, PM25_24H_C,PM10_24H_C ,
O3_8H_C);
dt.Dispose();
dt2.Dispose();
dt3.Dispose();
return AQI;
}
重新開了一個 Winform 專案,結構如下。
LevelType
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AQI
{
/// <summary>
/// AQI 等級
/// </summary>
public enum LevelType
{
L1 = 1,
L2,
L3,
L4,
L5,
L6,
L7,
}
}
PollutantType
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AQI
{
/// <summary>
/// 汙染物類型
/// </summary>
public enum PollutantType
{
O3_8hr,
O3_1hr,
PM2_5,
PM10,
CO_8hr,
SO2_1hr,
SO2_8hr,
NO2_1hr
}
}
AQI_Table
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
namespace AQI
{
/// <summary>
/// 空氣品質指標對照表
/// </summary>
public class AQI_Table
{
public decimal? O3_1hr_low { get; set; }
public decimal? O3_1hr_hight { get; set; }
public decimal? O3_8hr_low { get; set; }
public decimal? O3_8hr_hight { get; set; }
public decimal? SO2_1hr_low { get; set; }
public decimal? SO2_1hr_hight { get; set; }
public decimal? SO2_8hr_low { get; set; }
public decimal? SO2_8hr_hight { get; set; }
public decimal? CO_8hr_low { get; set; }
public decimal? CO_8hr_hight { get; set; }
public decimal? NO2_1hr_low { get; set; }
public decimal? NO2_1hr_hight { get; set; }
public decimal? PM2_5_low { get; set; }
public decimal? PM2_5_hight { get; set; }
public decimal? PM10_low { get; set; }
public decimal? PM10_hight { get; set; }
public int AQI_low { get; set; }
public int AQI_hight { get; set; }
public LevelType LevelType { get; set; }
public string Text { get; set; }
public Color Color { get; set; }
public string PicPath { get; set; }
}
}
AQI_Table_Ex
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
namespace AQI
{
public static class AQI_Table_Ex
{
/// <summary>
/// 產生空氣品質指標對照表資料
/// </summary>
/// <returns></returns>
public static List<AQI_Table> Create()
{
var table = new List<AQI_Table>
{
new AQI_Table
{
LevelType = LevelType.L1,
AQI_low = 0,
AQI_hight = 50,
O3_8hr_low = 0.000m,
O3_8hr_hight = 0.054m,
O3_1hr_low = null,
O3_1hr_hight = null,
PM2_5_low = 0.0m,
PM2_5_hight = 15.4m,
PM10_low = 0m,
PM10_hight = 54m,
CO_8hr_low = 0m,
CO_8hr_hight = 4.4m,
SO2_1hr_low = 0m,
SO2_1hr_hight = 35m,
SO2_8hr_low = null,
SO2_8hr_hight = null,
NO2_1hr_low = 0m,
NO2_1hr_hight = 53m,
Text = "良好",
Color = Color.Green,
PicPath = "picture1.png",
},
new AQI_Table
{
LevelType = LevelType.L2,
AQI_low = 51,
AQI_hight = 100,
O3_8hr_low = 0.055m,
O3_8hr_hight = 0.070m,
O3_1hr_low = null,
O3_1hr_hight = null,
PM2_5_low = 15.5m,
PM2_5_hight = 35.4m,
PM10_low = 55m,
PM10_hight = 125m,
CO_8hr_low = 4.5m,
CO_8hr_hight = 9.4m,
SO2_1hr_low = 36m,
SO2_1hr_hight = 75m,
SO2_8hr_low = null,
SO2_8hr_hight = null,
NO2_1hr_low = 54m,
NO2_1hr_hight = 100m,
Text = "普通",
Color = Color.Yellow,
PicPath = "picture2.png",
},
new AQI_Table
{
LevelType = LevelType.L3,
AQI_low = 101,
AQI_hight = 150,
O3_8hr_low = 0.071m,
O3_8hr_hight = 0.085m,
O3_1hr_low = 0.125m,
O3_1hr_hight = 0.164m,
PM2_5_low = 35.5m,
PM2_5_hight = 54.4m,
PM10_low = 126m,
PM10_hight = 254m,
CO_8hr_low = 9.5m,
CO_8hr_hight = 12.4m,
SO2_1hr_low = 76m,
SO2_1hr_hight = 185m,
SO2_8hr_low = null,
SO2_8hr_hight = null,
NO2_1hr_low = 101m,
NO2_1hr_hight = 360m,
Text = "對敏感族群\n不健康",
Color = Color.Orange,
PicPath = "picture3.png",
},
new AQI_Table
{
LevelType = LevelType.L4,
AQI_low = 151,
AQI_hight = 200,
O3_8hr_low = 0.086m,
O3_8hr_hight = 0.105m,
O3_1hr_low = 0.165m,
O3_1hr_hight = 0.204m,
PM2_5_low = 54.5m,
PM2_5_hight = 150.4m,
PM10_low = 255m,
PM10_hight = 354m,
CO_8hr_low = 12.5m,
CO_8hr_hight = 15.4m,
SO2_1hr_low = 186m,
SO2_1hr_hight = 304m,
SO2_8hr_low = 186m,
SO2_8hr_hight = 304m,
NO2_1hr_low = 361m,
NO2_1hr_hight = 649m,
Text = "對所有族群\n不健康",
Color = Color.Red,
PicPath = "picture4.png",
},
new AQI_Table
{
LevelType = LevelType.L5,
AQI_low = 201,
AQI_hight = 300,
O3_8hr_low = 0.106m,
O3_8hr_hight = 0.200m,
O3_1hr_low = 0.205m,
O3_1hr_hight = 0.404m,
PM2_5_low = 150.5m,
PM2_5_hight = 250.4m,
PM10_low = 355m,
PM10_hight = 424m,
CO_8hr_low = 15.5m,
CO_8hr_hight = 30.4m,
SO2_1hr_low = null,
SO2_1hr_hight = null,
SO2_8hr_low = 305m,
SO2_8hr_hight = 604m,
NO2_1hr_low = 650m,
NO2_1hr_hight = 1249m,
Text = "非常不健康",
Color = Color.Purple,
PicPath = "picture5.png",
},
new AQI_Table
{
LevelType = LevelType.L6,
AQI_low = 300,
AQI_hight = 400,
O3_8hr_low = null,
O3_8hr_hight = null,
O3_1hr_low = 0.405m,
O3_1hr_hight = 0.504m,
PM2_5_low = 250.5m,
PM2_5_hight = 350.4m,
PM10_low = 425m,
PM10_hight = 504m,
CO_8hr_low = 30.5m,
CO_8hr_hight = 40.4m,
SO2_1hr_low = null,
SO2_1hr_hight = null,
SO2_8hr_low = 605m,
SO2_8hr_hight = 804m,
NO2_1hr_low = 1250m,
NO2_1hr_hight = 1649m,
Text = "危害",
Color = Color.DarkRed,
PicPath = "picture6.png",
},
new AQI_Table
{
LevelType = LevelType.L7,
AQI_low = 400,
AQI_hight = 500,
O3_8hr_low = null,
O3_8hr_hight = null,
O3_1hr_low = 0.505m,
O3_1hr_hight = 0.604m,
PM2_5_low = 350.5m,
PM2_5_hight = 500.4m,
PM10_low = 505m,
PM10_hight = 604m,
CO_8hr_low = 40.5m,
CO_8hr_hight = 50.4m,
SO2_1hr_low = null,
SO2_1hr_hight = null,
SO2_8hr_low = 805m,
SO2_8hr_hight = 1004m,
NO2_1hr_low = 1650m,
NO2_1hr_hight = 2049m,
Text = "危害",
Color = Color.DarkRed,
PicPath = "picture7.png",
},
};
return table;
}
/// <summary>
/// 計算 AQI
/// </summary>
public static int CalcAQI(this List<AQI_Table> airQualityTable,
decimal? O3_8hr = null,
decimal? O3_1hr = null,
decimal? PM2_5 = null,
decimal? PM10 = null,
decimal? CO_8hr = null,
decimal? SO2_1hr = null,
decimal? NO2_1hr = null)
{
//汙染物陣列
var pollutantList = new List<Tuple<PollutantType, decimal>>();
if (O3_8hr.HasValue)
pollutantList.Add(new Tuple<PollutantType, decimal>
(PollutantType.O3_8hr, O3_8hr.Value));
if (O3_1hr.HasValue)
pollutantList.Add(new Tuple<PollutantType, decimal>
(PollutantType.O3_1hr, O3_1hr.Value));
if (PM2_5.HasValue)
pollutantList.Add(new Tuple<PollutantType, decimal>
(PollutantType.PM2_5, PM2_5.Value));
if (PM10.HasValue)
pollutantList.Add(new Tuple<PollutantType, decimal>
(PollutantType.PM10, PM10.Value));
if (CO_8hr.HasValue)
pollutantList.Add(new Tuple<PollutantType, decimal>
(PollutantType.CO_8hr, CO_8hr.Value));
if (SO2_1hr.HasValue)
pollutantList.Add(new Tuple<PollutantType, decimal>
(PollutantType.SO2_1hr, SO2_1hr.Value));
if (NO2_1hr.HasValue)
pollutantList.Add(new Tuple<PollutantType, decimal>
(PollutantType.NO2_1hr, NO2_1hr.Value));
var pollutantRowList = pollutantList.Select(it =>
{
//產生可動態取得 low、high 的表達式樹
var pollutantName = it.Item1.ToString();
var type = typeof(AQI_Table);
var itParam = Expression.Parameter(type, "it");
var lowGetter = Expression.Property(itParam, type.GetProperty($"{pollutantName}_low"));
var highGetter = Expression.Property(itParam, type.GetProperty($"{pollutantName}_hight"));
var getLow = Expression.Lambda<Func<AQI_Table, decimal?>>(lowGetter, itParam).Compile();
var getHigh = Expression.Lambda<Func<AQI_Table, decimal?>>(highGetter, itParam).Compile();
var pollutantType = it.Item1;
var C = it.Item2;
//查表
var row = airQualityTable
.Where(itt => C >= getLow(itt) && C <= getHigh(itt))
.FirstOrDefault();
//查不到回傳 null
return row == null ? null : new
{
pollutantType = pollutantType,
row = row,
C = C,
Clow = getLow(row).Value,
Chigh = getHigh(row).Value,
Ilow = row.AQI_low,
Ihigh = row.AQI_hight,
};
});
//IAQI 計算公式
var calc = (Func<decimal, decimal, decimal, int, int, int>)((C, Clow, Chigh, Ilow, Ihigh) =>
{
return (int)Math.Ceiling((Ihigh - Ilow) / (Chigh - Clow) * (C - Clow) + Ilow);
});
//計算 IAQI
var IAQI = pollutantRowList.Where(it => it != null)
.Select(it => new
{
pollutantType = it.pollutantType,
IAQI = calc(it.C, it.Clow, it.Chigh, it.Ilow, it.Ihigh),
});
//算出最大值
return IAQI.Max(it => it.IAQI);
}
}
}
Form1
using AQI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AQI計算
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var O3_8hr = get_O3_8hr_average();
var O3_1hr = get_O3_1hr_average();
var PM2_5 = get_PM2_5_average();
var PM10 = get_PM10_average();
var CO_8hr = get_CO_8hr_average();
var SO2_1hr = get_SO2_1hr_average();
var NO2_1hr = get_NO2_1hr_average();
var table = AQI_Table_Ex.Create();
//計算 AQI
var AQI = table.CalcAQI(
O3_8hr: O3_8hr,
O3_1hr: O3_1hr,
PM2_5: PM2_5,
PM10: PM10,
CO_8hr: CO_8hr,
SO2_1hr: SO2_1hr,
NO2_1hr: NO2_1hr);
//取得顏色圖片等等資訊
var item = table
.Where(it => it.AQI_low <= AQI && it.AQI_hight >= AQI)
.FirstOrDefault();
}
public decimal get_O3_8hr_average()
{
//需實作
return default(decimal);
}
public decimal get_O3_1hr_average()
{
//需實作
return default(decimal);
}
public decimal get_PM2_5_average()
{
//需實作
return default(decimal);
}
public decimal get_PM10_average()
{
//需實作
return default(decimal);
}
public decimal get_CO_8hr_average()
{
//需實作
return default(decimal);
}
public decimal get_SO2_1hr_average()
{
//需實作
return default(decimal);
}
public decimal get_NO2_1hr_average()
{
//需實作
return default(decimal);
}
}
}
大大感謝, 我試試看..
大概就是
把class 不要塞在同一個.cs 檔
創造很多個弄成各項類別,和函式
在從最原本Windowfrom.cs
去讀其他的.cs 檔
其他的.cs 資料餵入 Windowfrom.cs
把要附加的功能等等,比如連線資料庫段,把數值丟到excel欄位等等..
都寫在Windowfrom.cs裡
謝謝大大
哈哈哈,您說的很對!!!
其實也就是您一開始的疑問。
如何做成 function,如何綁成 class。
@fy 大大謝謝您
恩...怎辦 想問你一個問題 Omg
怎辦
我最新版VS2017 更新到 8月了
我C# 升級到 7.2..了說
說小括號無效
括號, 逗號,分號 我都試過 ,刪除 重新排列位置..
最後一個參數多了逗號。
大大 後面 接的型別是不是 只能 Int 型別?
對,AQI 是整數,我用 int 當回傳值。
可是後面這段
var AQI = table.CalcAQI(
O3_8hr: O3_8H_C,
O3_1hr: dt6, //小時濃度
PM2_5: PM25_24H_C ,
PM10: PM10_24H_C,
CO_8hr: CO_8H_C,
SO2_1hr: dt8 , //小時濃度
NO2_1hr: dt9 ) ;
其中 幾項是 double 型別..
在那之前 使用大大 您之前用的語法,把移動平均都改成都改成int 型別嗎?
可是我是覺得 有點怪怪 因為移動平均, 是有小數點的說..
那至於上面 dt8,9 之類
是從資料庫接數據來的,表上寫小時平均,沒錯的話,因該是小時濃度
移動平均那邊不用改,參數是 double 沒錯 (我是用 decimal),回傳(AQI)是 int,不衝突。
大大不好意思.. 可是為什麼會 紅色蝌蚪阿.. Help
照理說這樣因該沒問題啊
我是用 decimal 吧,哈哈哈
沒事了,要改一下 型別.. 謝謝大大
不好意思
@fy 大大 請問
可是後面數值,好像有進入
卻不能轉換
可以Help 嗎?
這樣看不太出來,要先把 try catch 拿掉看出錯在哪一段程式。
就是那一大段 測出來Bug 是白色圈起來那一大段 進去不了AQI_Table_Ex.CS
類型轉換有問題 , 可是理論上 因該OK
@f 大大 Help..
第二段程式碼不用判斷了,
number >= 50成立後面都不會執行了,
所以永遠都是 良好,
如果從後面的條件往回判斷倒是可以,
這你要自己思考一下...
另外"良好"本身就是字串了,不需要再ToString了,
是不會錯誤只是多此一舉。