今、家電のリモコンが出す赤外線のデータをarduinoで拾って、PCにデータを送って、それをCSVファイルにして保存しようとしてます。
データ量は多くないし、修正はエディターでできるように出力ファイルもCSV形式にしたのですが、ボタン一発でソートする機能を付けたくなってソートロジックを調べました。
MFCのCArrayは便利なので、よく使っています。CArrayのなかにstructを追加でストアしていって、必要な時点でボタン一発でソートします。
例えば、以下の struct と CArray。
ソートキーは kisyuID と buttonID の二つ。
■以下はロジック確認用の実験プログラム
頭に0を入れてるデータの例
ソートロジック「qsort 1」 はネットで見つけた2項目のサンプルからCArray, CString のソートに合わせて修正したもの。
「ソートパラメータ」は「CStringでソート」。
実行させると、下のようにソートされました。
文字列を int にしてからクイックソートした場合。
頭に0を入れて桁数をそろえてあるので結果は同じ。
ロジックは以下のとおり。
■文字列のまま(CString)クイックソート
// KisyuID列の比較関数(CString編)
int cmp_Kisyu_CString(DATA* a, DATA* b)
{
DATA* pA = (DATA*)a;
DATA* pB = (DATA*)b;
return (pA->kisyuID.Compare(pB->kisyuID));
}
// ButtonID列の比較関数(CString編)
int cmp_Button_CString(DATA* a, DATA* b)
{
DATA* pA = (DATA*)a;
DATA* pB = (DATA*)b;
return (pA->buttonID.Compare(pB->buttonID));
}
// 比較関数(CString編)
int cmp_CString(void* context, const void* item1, const void* item2)
{
// 比較関数リスト
// 比較対象列分の比較関数を作成し、設定する。
int(*func[])(DATA * pa, DATA * pb) =
{ &cmp_Kisyu_CString , &cmp_Button_CString };
DATA* pItem1 = (DATA*)item1;
DATA* pItem2 = (DATA*)item2;
for (int i = 0; i < sizeof(func) / sizeof(func[0]); i++)
{ // 比較対象列分繰り返す
int ret = func[i](pItem1, pItem2); // 比較関数実行
if (ret != 0) // 前後が決定したか
{
return ret;
}
}
// 全ての比較関数を実行しても前後関係が決定しないので、
// 同等なデータと判断
return 0;
}
qsort_s((void*)&aryData[0], aryData.GetSize(), sizeof(DATA), cmp_CString, NULL);
■文字列をintに変換してからクイックソート
// KisyuID列の比較関数(intに変換編)
int cmp_Kisyu_int(DATA* a, DATA* b)
{
int n1 = _ttoi(a->kisyuID);
int n2 = _ttoi(b->kisyuID);
int wk3;
if (n1 > n2) wk3 = 1;
else if (n1 < n2) wk3 = -1;
else wk3 = 0;
return wk3;
}
// ButtonID列の比較関数(intに変換編)
int cmp_Button_int(DATA* a, DATA* b)
{
int n1 = _ttoi(a->buttonID);
int n2 = _ttoi(b->buttonID);
int wk3;
if (n1 > n2) wk3 = 1;
else if (n1 < n2) wk3 = -1;
else wk3 = 0;
return wk3;
}
// 比較関数(intに変換編)
int cmp_int(void* context, const void* item1, const void* item2)
{
// 比較関数リスト
// 比較対象列分の比較関数を作成し、設定する。
int(*func[])(DATA * pa, DATA * pb) = { &cmp_Kisyu_int , &cmp_Button_int };
DATA* pItem1 = (DATA*)item1;
DATA* pItem2 = (DATA*)item2;
for (int i = 0; i < sizeof(func) / sizeof(func[0]); i++)
{ // 比較対象列分繰り返す
int ret = func[i](pItem1, pItem2); // 比較関数実行
if (ret != 0) // 前後が決定したか
{
return ret;
}
}
// 全ての比較関数を実行しても前後関係が決定しないので、
// 同等なデータと判断
return 0;
}
qsort_s((void*)&aryData[0], aryData.GetSize(), sizeof(DATA), cmp_int, NULL);
■比較関数ロジックを少しわかり易く書き方を変えると
//ロジック書き換えの比較関数(CString編)
int cmp_2_CString(void* context, const void* a, const void* b)
{
int ret = 0;
DATA* pA = (DATA*)a;
DATA* pB = (DATA*)b;
ret = cmp_Kisyu_CString(pA, pB); // 比較関数実行
if (ret != 0) // 前後が決定したか
{
return ret;
}
ret = cmp_Button_CString(pA, pB); // 比較関数実行
if (ret != 0) // 前後が決定したか
{
return ret;
}
// 全ての比較関数を実行しても前後関係が決定しないので、
// 同等なデータと判断
return 0;
}
qsort_s((void*)&aryData[0], aryData.GetSize(), sizeof(DATA), cmp_2_CString, NULL);
//ロジック書き換えの比較関数(intに変換編)
int cmp_2_int(void* context, const void* a, const void* b)
{
int ret = 0;
DATA* pA = (DATA*)a;
DATA* pB = (DATA*)b;
ret = cmp_Kisyu_int(pA, pB); // 比較関数実行
if (ret != 0) // 前後が決定したか
{
return ret;
}
ret = cmp_Button_int(pA, pB); // 比較関数実行
if (ret != 0) // 前後が決定したか
{
return ret;
}
// 全ての比較関数を実行しても前後関係が決定しないので、
// 同等なデータと判断
return 0;
}
qsort_s((void*)&aryData[0], aryData.GetSize(), sizeof(DATA), cmp_2_int, NULL);
書き換えた qsort のロジックでも正しくソートできている。
バブルソートのロジックは以下のとおり。
バブルソート(CString変換編)
void bubble_sort_button_CString(CArray & aryData, int n)
{
int ret = 0;
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
ret = aryData[j].buttonID.Compare(aryData[j + 1].buttonID);
if (ret == 1) // [j] > [j + 1] だった
{
swap(aryData[j], aryData[j + 1]);
// 要素へのポインタを渡してスワップ
}
}
}
}
void bubble_sort_kisyu_CString(CArray & aryData, int n)
{
for (int i = 0; i < n - 1; i++)
{
int ret = 0;
for (int j = 0; j < n - i - 1; j++)
{
ret = aryData[j].kisyuID.Compare(aryData[j + 1].kisyuID);
if (ret == 1) // [j] > [j + 1] だった
{
swap(aryData[j], aryData[j + 1]);
// 要素へのポインタを渡してスワップ
}
}
}
}
bubble_sort_button_CString(aryData, aryData.GetSize());
bubble_sort_kisyu_CString(aryData, aryData.GetSize());
バブルソート(intに変換編)
void bubble_sort_button_int(CArray &aryData, int n)
{
int a = 0;
int b = 0;
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
a = _ttoi(aryData[j].buttonID);
b = _ttoi(aryData[j + 1].buttonID);
if (a > b) // 右隣が小さければ入れ替える
{
swap(aryData[j], aryData[j + 1]);
// 要素へのポインタを渡してスワップ
}
}
}
}
void bubble_sort_kisyu_int(CArray &aryData, int n)
{
int a = 0;
int b = 0;
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
a = _ttoi(aryData[j].kisyuID);
b = _ttoi(aryData[j + 1].kisyuID);
if (a > b) // 右隣が小さければ入れ替える
{
swap(aryData[j], aryData[j + 1]);
// 要素へのポインタを渡してスワップ
}
}
}
}
bubble_sort_button_int(aryData, aryData.GetSize());
bubble_sort_kisyu_int(aryData, aryData.GetSize());
■ソートするキーデータの桁が不揃いの場合
■CStringのままではソートできない
■intに変換してからソートする
以上