重複のアルゴリズム(配列)
前回は、相互チェック(重複エラーチェック)を2重ループで実装した。しかし、ループを1回で実装することもできる。
前回の内容は下記参照。
画面イメージ
一覧形式の入力項目にエラーチェックを実装しようとする。
製品入庫登録 | ||||||||||||||||||
|
仕様
①登録ボタンを押下後、製品番号が重複している場合、エラーを表示する。
エラーを画面上部に表示する場合
重複データを単純に知らせたい場合、画面の上部もしくはJavaScriptのalertでポップアップエラーを表示することがある。
製品入庫登録 | ||||||||||||||||||
|
ソース
ボタンを押した時に呼び出される関数は、下記に記載。
- function buttonfunction1() {
- var ary = new Array(5);
- ary[0]=document.getElementById('seiban1_1').value;
- ary[1]=document.getElementById('seiban1_2').value;
- ary[2]=document.getElementById('seiban1_3').value;
- ary[3]=document.getElementById('seiban1_4').value;
- ary[4]=document.getElementById('seiban1_5').value;
- var count = 0;
- var errorFlg = false;
- for (i = 0; i < 5; i++) {
- if (ary[i] == "") {
- count++;
- continue;
- }
- if (ary.indexOf(ary[i]) < i){
- errorFlg = true;
- }
- }
- if (count == 5) {
- document.getElementById('msg1').innerHTML = "<font color='red'>登録データがありません。</font>";
- return;
- }
- if (errorFlg) {
- document.getElementById('msg1').innerHTML = "<font color='red'>製品番号が重複しています。</font>";
- } else {
- document.getElementById('msg1').innerHTML = "登録しました。";
- }
- }
解説
大きな処理は3つ。
配列・変数の定義、重複判定処理、メッセージ・エラー表示。
前回との変更点としては、重複判定はFor文のみで実装している。
- 2~7行目 入力項目を配列にセット。
- 9行目 全てが空行か判定する変数(※1)
- 10行目 重複行があるか判定する変数(※2)
- 11行目 For文 全行判定します。
- 12~15行目 空行の場合、次の行に移る。空行判定変数(※1)にインクリメント。
- 16~18行目 現在行の値が配列の何番目か取得、現在行より小さい場合は重複エラー変数(※2)をtrue。
- 21~24行目 空行判定変数(※1)が全行の場合、エラーを表示。処理終了。
- 27行目 重複エラー変数(※2)がtrueの場合、エラーを表示。
- 29行目 そうでない場合、登録成功。
計算量の確認
上記のソースは、前回と比べると、試行回数がnとなっており、行数によって累次的に計算量が増加はしない。
結論
重複のエラーが存在するかだけを判定する場合は、For文1回だけで判定することができる。
SQL克服!COALESCEについて
普段何気なく使っていた「COALESCE(コアレス)」。ちょっと思っていたのと違ったので、少しまとめてみました。
英単語としての意味
主な意味は、「癒合(ゆごう)する」「合体する」「複数のものを1つにまとめる」という意味がある。
関数
COALESCEは、NULLでない最初の引数を返します。 全ての引数がNULLの場合にのみNULLが返されます。
つまり、複数の項目のうち初めのNULLでない値を表示する。ということ。
どこに勘違い…?
ここで、複数というのがミソ。
普段COALESCEを見る場合は、『値がない場合に〇〇を表示する』と言ったもの。
COALESCE(table.num, 0)
これが、勘違いの原因。引数は2つだけと思っていた。ORACLEでいうNVL関数(Null Value Logic)と同じものだとばかり…。
さて、このような状態で複数の場合で表示してほしいと言われました。『例えば、電話番号の欄には、従業員電話番号1、なければ従業員電話番号2、なければ"該当データなし"と表示』
複数の場合ね、CASE文でもできそうだけど、COALESCEの入れ子の方法を探してみることに…。
でも、探しても見つからない。仕方なく我流で実装してみることに。
COALESCE(emp.tel1, COALESCE(emp.tel2, '該当データなし'))
実行してみると、想定通り。よしできた。
ちょっと待って!!
COALESCEは複数できるの!だから上記のソースは下のように書き換えられる。
COALESCE(emp.tel1, emp.tel2, '該当データなし')
これで、とてもスマートになった。
同じような勘違いをしている人が減りますように。
重複チェックのアルゴリズム(2重ループ)
仕事をしていると、相互チェック(重複エラーチェック)を実装することがある。しかし、アルゴリズムを考えるのが苦手だ。ここにメモとして残しておきたい。
画面イメージ
一覧形式の入力項目にエラーチェックを実装しようとする。
製品入庫登録 | ||||||||||||||||||
|
仕様
①登録ボタンを押下後、製品番号が重複している場合、エラーを表示する。
エラーを画面上部に表示する場合
重複データを単純に知らせたい場合、画面の上部もしくはJavaScriptのalertでポップアップエラーを表示することがある。
製品入庫登録 | ||||||||||||||||||
|
ソース
ボタンを押した時に呼び出される関数は、下記に記載。
- function buttonfunction1() {
- var ary = new Array(5);
- ary[0] = document.getElementById('seiban1_1').value;
- ary[1] = document.getElementById('seiban1_2').value;
- ary[2] = document.getElementById('seiban1_3').value;
- ary[3] = document.getElementById('seiban1_4').value;
- ary[4] = document.getElementById('seiban1_5').value;
- var count = 0;
- var errorFlg = false;
- for (i = 0; i < 5; i++) {
- if (ary[i] == "") {
- count++;
- continue;
- }
- for (j = 0; j < 5; j++) {
- if (i == j) {
- continue;
- }
- if (ary[i] == ary[j]) {
- errorFlg = true;
- }
- }
- }
- if (count == 5) {
- document.getElementById('msg1').innerHTML = "<font color='red'>登録データがありません。</font>";
- return;
- }
- if (errorFlg) {
- document.getElementById('msg1').innerHTML = "<font color='red'>製品番号が重複しています。</font>";
- } else {
- document.getElementById('msg1').innerHTML = "登録しました。";
- }
- }
解説
大きな処理は3つ。
配列・変数の定義、重複判定処理、メッセージ・エラー表示。
これに付け加えて重複判定ではForの入れ子で実装している。
- 2~7行目 入力項目を配列にセット。
- 9行目 全てが空行か判定する変数(※1)
- 10行目 重複行があるか判定する変数(※2)
- 11行目 For文 全行判定します。
- 12~16行目 空行の場合、次の行に移る。空行判定変数(※1)にインクリメント。
- 17行目 For文 現在行との重複行を全行判定します。
- 18~20行目 自行の場合は、次の行に移る。
- 21~23行目 値が同じ場合、重複エラー変数(※2)をtrue。
- 26~29行目 空行判定変数(※1)が全行の場合、エラーを表示。処理終了。
- 31行目 重複エラー変数(※2)がtrueの場合、エラーを表示。
- 33行目 そうでない場合、登録成功。
今回は、全行が空行か判定を重複判定処理に組み込んでしまったが、これは重複判定処理の前に実装しておいたほうがいい。 だって、入力行数が100行になったら、100×100=10,000回施行してしまう。
というわけでこれを改善していこう。
問題はなんだったのか?
上記のソースの問題は、行数がn行あると、試行回数がn2になってしまう。この考え方を計算量オーダーとか言ったりするが、これはまたの話。
さて、このことから重複計算処理になにかしらの手を加えなければならない。
ここで、机上デバッグしてみる。
机上デバッグ
ここでの机上デバッグは、ソースコードの妥当性というよりも変数遷移の書き出しをしてみるとする。
i = 0 のとき、
j = 0 のとき、i 行と同じなので重複判定対象外。
j = 1 のとき、i 行と重複判定。
・・・
j = 4 のとき、i 行と重複判定。
i = 1 のとき、
j = 0 のとき、i 行と重複判定。
j = 1 のとき、i 行と同じなので重複判定対象外。
j = 2 のとき、i 行と重複判定。
・・・
j = 4 のとき、i 行と重複判定。
・・・
i = 4 のとき、
j = 0 のとき、i 行と重複判定。
j = 1 のとき、i 行と重複判定。
・・・
j = 4 のとき、i 行と同じなので重複判定対象外。
かなり長くなってしまったが、おやおや、(i = 0, j = 1)の判定と(i = 1, j = 0)の判定は同じですよね? だって同じ配列なんですもん。
ということは、i = 1 のときは、j = 2 から判定すればいいんですよね?
(もしくは、i = 3 のときは 0,1,2を判定すればよい。)
重複判定処理 修正版①
重複判定を自行より大きい行とする場合。
- for (i = 0; i < 5; i++) {
- if (ary[i] == "") {
- count++;
- continue;
- }
- for (j = i + 1; j < 5; j++) {
- if (ary[i] == ary[j]) {
- errorFlg = true;
- }
- }
- }
重複判定処理 修正版②
重複判定を自行までの行とする場合。
- for (i = 0; i < 5; i++) {
- if (ary[i] == "") {
- count++;
- continue;
- }
- for (j = 0 j < i; j++) {
- if (ary[i] == ary[j]) {
- errorFlg = true;
- }
- }
- }
結論
修正版を使うと、ソースをステップ数(計算量オーダー)が減ってスリムに見えてくるようになりましたね。
次は、各行にエラーを表示する処理を考えます。
より計算量を減らす考え方はこちら
Thunderbirdで添付ファイルが保存できない
メールソフトのThunderbirdで添付ファイルがうまく保存できない。一時期頻発していて、最近ちゃんと保存できるようになっていたが、今日は違うメッセージが表示された。
添付ファイルがなんだかおかしいぞ
課内メーリングリストの資料を保存しようとすると、
この添付ファイルは空です。メッセージの送信者に確認してください。内容によってはファイアウォールやウイルス対策ソフトが添付ファイルを壊すことがあります。
なんだこれは!?今までこんなメッセージ表示されていなかったのに…
保存してみると、ウインドウ下部のステータスに
メッセージをダウンロードしています…
と固まったまま、当然ファイルは0KB。
初めは、複合機からスキャンしたPDFで発生していたこの問題。ダウンロードしたPDFは50KBくらいのデータだが、開いてみると壊れている。
Adobe Reader で「<ファイル名>」を開けませんでした。 ファイルの種類がサポートされていないか、またはファイルが破損している可能性があります。例えば、電子メールの添付文書として送信され、正しくデコードされなかったことなどが考えられます。
Tunderbirdで添付ファイルが空になる件
調べてみると、こんな記事を発見。
まさに探していた現象ではないか!?
記事の内容通り、現象は「メッセージフィルタによって移動された先のフォルダ」で発生しており「受信トレイに戻すと添付ファイルが開ける」ようになった。
メッセージフィルタによる移動が悪さをしていたのか?
フォルダーの修復
というわけで、振り分け先のフォルダを右クリックしてプロパティを開きます。
初回実行すると、フォルダ内のメールの量にもよるが、1~2分で処理が完了する。再度、添付ファイルを選択すると、ちゃんと保存ができる!
原因はなんだったのか
調べてみると、レアケースらしいようでよくわからない。メッセージ移動の際に添付ファイルの情報が抜け落ちているのかもしれない、など。
こちらのサイトでも、プロファイルの作り直しもしくは上記の方法を検討したようです。
wimblog » Thunderbirdの添付ファイルが0byteになるあれ
メッセージはフォルダ移動じゃなくて、検索フォルダを使用したほうがいいのかもしれないね。
Excelでセルの色付けを1発で実行する方法
普段Excelを使っていて、セルの色付けをショートカットキーでする方法がないかなと思うことがある。
実は、色を付けるショートカットキーはない。
でも諦めないで!セルに色を付ける方法は沢山あるんだから。
今回はこの表に色を付けるとしよう。
特定のセルだけ色を付けたい
ある特定の条件のセルを塗りたい場合は、置換を使うとよい。
[ホーム]-[編集]-[検索と選択]-[置換]
から、検索する文字列と置換後の文字列の両方に色を付けたい文字列を入力する。
オプションを選択し、置換後の文字列の書式に塗りたい色を選択する。
すべて置換を選択すると、セルの色付けが完了する。
1セルずつ色付けたい
いや違うんだ!手元の資料やほかの資料と消込をしたくて、色を塗りたいんだ!
いちいちマウスを動かすのは面倒だから、キーボードでかっこよく作業したいのに…という場合は、「直前の作業を繰り返す」を実行すれば良い。
直前の作業を繰り返すキーは
直前の作業を繰り返す: |
F4
|
一度セルを塗りつぶした後に、
違うセルを選択して F4 を押すと、直前の作業を繰り返すのでセルに色が付く。
このショートカットキーは、元に戻す(Ctrl+Z)の対となる
でも同じことができる。
直前の作業を繰り返す: |
Ctrl
|
+ |
Y
|
この作業は、セルの書式設定でも繰り返し作業ができるため、色付けのほかに太字や斜体、なども変えることができる。
まとめ
特定の条件だけセルの色を付ける:
検索する文字列と置換後の文字列を同じにして、オプションから書式を選択する。
1つずつ色を付ける:
直前の作業を繰り返す: |
F4
|
直前の作業を繰り返す: |
Ctrl
|
+ |
Y
|