上週五的時候小蛇蛇青在GT里淚流滿面表示他老闆要他處理一份包含了一萬五千條數據的表格,需要把每一條數據和整個表格其他所有數據進行比對。我驚異地問:你就打算這麼肉眼篩選么……!他默默表示是這樣的。我在OTZ的同時決定幫他寫一個篩選器。

其實這是一個無比簡單的程序,就是獲取Excel文件,獲取需要比較的Columns,然後再遍歷一次Excel,排除當前行進行一一對比,然後把符合條件的數據存到DataTable中。青需要的篩選條件如下:當D單元格和N單元格的差值不等於500的時候,比較D和D(i),以及N和N(i)。當兩個數據的差值都小於500的時候,即是符合條件的數據。

初期我算法如下:

for (int i = 0; i < sheet.Rows.Count - 1; i++)
{
int D1 = int.Parse(sheet[i + 1, 3].Value.ToString());
int N1 = int.Parse(sheet[i + 1, 13].Value.ToString());

for (int j = 0; j < sheet.Rows.Count - 1; j++)
{
int D2 = int.Parse(sheet[j + 1, 3].Value.ToString());
int N2 = int.Parse(sheet[j + 1, 13].Value.ToString());

int D = Math.Abs(D2 - D1);
int N = Math.Abs(N2 - N1);

if (D < 500 && N < 500 && Math.Abs(D1 - N1) != 500)
{
DataRow dr = dt.NewRow();
//寫入該行的數據
dt.Rows.Add(dr);
}
}
}



可以看到,這段代碼絕對是很坑爹的。首先就是i和j都遍歷了整個Excel,但是沒有排除i=j的情況,那麼必然存在D-N!=500,然後因為i=j所以Di-Dj=0,Ni-Nj=0。接著就輸出數據了這樣坑爹的結果……
最後執行這個程序,運算出來的結果大概是200萬條……無限坑爹……於是青淚流滿面地去肉眼篩選去了。

第二天我們繼續討論這段代碼。我設計了一個逆序遍歷的思路,也就是加了這一句:

for (int j = sheet.Rows.Count; (i + 2) < j; j--)

可是這樣的算法還是有問題,j拋棄(0-i)這一段,不符合要求,放棄。

我向青描述了我的算法構思,描述的過程中突然醒悟:之前設計的代碼,只要符合篩選條件,就會輸出一行i的數據。但是在Excel中,數據並不是唯一匹配的。所以無怪乎之前會輸出200萬條數據了。

因此,在執行i和j比較的循環的時候,只要有符合條件的輸出執行一次之後,應該立刻break這個循環,開始下一條循環。這時候青表示之前的篩選條件說漏了。他需要的篩選條件是:當C的值相當,也就是屬於同一條染色體的時候,才進行數據篩選。這時候首先進行Di-Ni!=500的判斷。然後進行ABS(Di-Dj)<500 && ABS(Ni-Nj)<500的篩選。之後,再追加一次ABS(Di-Nj)<500 && ABS(Ni-Dj)<500的篩選。

最終算法代碼如下:

for (int i = 0; i < sheet.Rows.Count - 1; i++)
{
    string C1 = sheet[i + 1, 2].Value.ToString();
    int D1 = Math.Abs(int.Parse(sheet[i + 1, 3].Value.ToString()));
    int N1 = Math.Abs(int.Parse(sheet[i + 1, 13].Value.ToString()));

    if (Math.Abs(D1 - N1) != 500)
    {

        //for (int j = sheet.Rows.Count; (i + 2) < j; j--)
        for (int j = 0; j < sheet.Rows.Count - 1; j++)
        {
            if (i != j)
            {
                string C2 = sheet[j + 1, 2].Value.ToString();
                int D2 = Math.Abs(int.Parse(sheet[j + 1, 3].Value.ToString()));
                int N2 = Math.Abs(int.Parse(sheet[j + 1, 13].Value.ToString()));

                int D = Math.Abs(D2 - D1);
                int N = Math.Abs(N2 - N1);
                int A = Math.Abs(D2 - N1);
                int B = Math.Abs(N2 - D1);

                if (C1 == C2)
                {

                    if (D < 500 && N < 500)
                    {
                        DataRow dr = dt.NewRow();
                        //輸出
                        dt.Rows.Add(dr);

                        break;
                    }
                    else
                    {
                        if (A < 500 && B < 500)
                        {
                            DataRow dr = dt.NewRow();
                            //輸出
                            dt.Rows.Add(dr);

                            break;
                        }
                    }
                }
            }
        }
    }
}

最後篩選了9000多條數據出來,經過青的肉眼檢查唔錯。他淚目表示:看著順眼多了……

哎,不會編程的科研人員上輩子都是那啥的天使……這種實驗對於青來說要做多少次……這數據要處理多少條……據他說他老闆一直是肉眼處理數據的……這,這得有多強大的耐心才能搞定啊OTZ!

順帶表示,我覺得我這個算法效率太低了,我相信一定有更佳的算法,希望高手能指教我一下XD。