


請問圖一 和 圖二 和 圖三 如果 分別各要寫成一個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了,
是不會錯誤只是多此一舉。