If文またはSelect文を効率よくコーディングするには?


ちき  2012-06-16 03:06:21  No: 143333  IP: 192.*.*.*

現在vb.netで開発中

編集判定の処理です。
判定する項目は
a,b,cです。

■説明
※フラグは編集しない条件の時にたつ
①aがbと同じ場合は以下の処理判定を行う。
②bが1かつ2かつcが3かつ4ならフラグを立てる
③bが2または3かつdが1かつ2かつ5ならフラグを立てる
④bが2または3かつdが1かつ2かつ5
⑤フラグが立たなかったら編集処理を行う
のような内容です。

こんな簡単な内容で申し訳ないのですがよろしくお願いします。

■コーディング

Dim flg as integer = 0

①If a = b then
② If b = 1 AndAlso c = 2 AndAlso  c = 3 AndAlso c = 4 then
     flg = 0
③  Elseif b = 2 OrElse b = 3 AndAlso  d = 1 AndAlse d = 2 AndAlso c = 5 then
     flg = 0 
④  Elseif b = 4 OrElse b = 5 AndAlse c = 6 OrElse c = 7 OrElse c = 8
     flg = 0
  End if

End if


⑤If flg = 0 then
  '編集処理を行う
End if

編集 削除
YuO  2012-06-16 08:49:40  No: 143334  IP: 192.*.*.*

根本的に条件がおかしいです。
bは一つの値しかとらないので,「bが1かつ2」は成立しません。
# 「かつ」は「両方が同時に成立」を意味します。

個人的には,こういうややこしい場合はメソッドに切り出します。
想像するに,こんな条件なのでしょうか。
Private Function IsEdit () As Boolean ' 編集「する」場合にTrueを返す。メソッド名は肯定的に付ける (Boolean型プロパティからの類推)。
    If a = b Then Return True
    Select Case b
        Case 1
            Return c <> 2 AndAlso c <> 3 AndAlso c <> 4
        Case 2, 3
            Return d <> 1 AndAlso d <> 2 AndAlso d <> 5
        Case 4, 5
            Return c <> 6 AndAlso c <> 7 AndAlso c <> 8
    End Select
    Return True
End Function

編集 削除
魔界の仮面弁士  2012-06-16 09:18:29  No: 143335  IP: 192.*.*.*

> bが1かつ2かつcが3かつ4ならフラグを立てる
たとえば、b が 2 で c が 3 のときは、上記条件に合致しませんよね。
この場合にフラグが立つ状況というのは、b と c それぞれに
何という数値が入っている場合のことでしょうか?


> Elseif b = 2 OrElse b = 3 AndAlso  d = 1 AndAlse d = 2 AndAlso c = 5 then
上記と同じ理由で、「d = 1 AndAlse d = 2」などは、条件として不自然です。
「d = 1 OrElse d = 2」とか、「x = 1 AndAlso y = 2」とか、
「d >= 1 AndAlso d <= 2」などであれば分かりますけれども。


> のような内容です。
そもそもの設問に無理がありますし、「フラグ」および変数 flg の意図も読み取れません。

この場合の flg とは、なにを管理する値なのでしょうか?

提示されたコードでは、初期値 0 に対して、各種条件で 0 をセットしてますが、
それってなにもしなくても同じことですよね。質問の意図が読み取れませんでした。


> こんな簡単な内容で申し訳ないのですがよろしくお願いします。

一般論として、「flg」のような変数名は付けるべきではありません。
flg = 0 がどういう状態を意味しているのか、コードを読む第三者には
伝わりませんし、flg = -1 や flg = 9999 が許容されるのかも不明です。

状態を表す変数を使うのであれば、
  Dim dataReady As Boolean
  If dataReady Then  'データの準備ができているとき

  Dim selectedReportType As ReportType
  If selectedReportType = ReportType.DailySales Then  '「日別売上」という帳票が選択されたとき
などのように、コメント無しでもある程度意味がつかめる名前にするべきですし、
値についても、0 や 1 といったマジックナンバーではなく、
Boolean、列挙型、定数値などを用いて表現するようにします。


また、If 文に付いてですが、あまり複雑な判定文とになるときには一時変数を利用します。たとえば、

  If document.AtEndOfStream() AndAlso Not inputError AndAlso MIN_LINES <= lineCount AndAlso lineCount <= MAX_LINES AndAlso Not ErrorProcessing() Then

のような長い判定文だと、コードの意図を読み取りにくいですが、

  Dim allDataRead As Boolean = document.AtEndOfStream() AndAlso Not inputError
  Dim legalLineCount As Boolean = MIN_LINES <= lineCount AndAlso lineCount <= MAX_LINES

  If allDataRead AndAlso legalLineCount AndAlso Not ErrorProcessing() Then

のようにまとめると、何をするための処理かが分かりやすくなります。



もう一つ、提示いただいたコードの
> c = 6 OrElse c = 7 OrElse c = 8
といった  Or の処理ですが、同じ値に対する判定数が多い場合には、
  Select Case c
    Case 6, 7, 8, 12
のように、Select Case を使って処理することができます。


ただし、
> b = 5 AndAlse c = 6 OrElse c = 7 OrElse c = 8
のように、他の変数の判定も行う場合は、Select Case では
対処しにくい場合があると思います。このような場合には、

Private editableColumns As New List(Of Integer)()
Private Sub Form1_Load(……
  editableColumns.Add(6)
  editableColumns.Add(7)
  editableColumns.Add(8)
  editableColumns.Add(12)
End Sub

のように、値の条件をあらかじめ配列やList型の変数にまとめておくと便利です。
そうすれば、
  If baseRow = 5 AndAlso (col = 6 OrElse col = 7 OrElse col = 8 OrElse col = 12) Then
のようなコードを
  If baseRow = 5 AndAlso editableColumns.Contains(col) Then
のようにまとめられるので、判定数が多くなっても対処しやすくなります。


もう一点。たとえば
  If b = 5 AndAlso c = 6 OrElse c = 7 OrElse c = 8 Then    '変更前
のようなコードの場合、括弧の併用を検討してみてください。たとえば、
  If (b = 5 AndAlso c = 6) OrElse (c = 7 OrElse c = 8) Then   'パターン1
  If  b = 5 AndAlso (c = 6 OrElse c = 7 OrElse c = 8)  Then   'パターン2
などに書き換えるという事です。(上記 2 つは、異なる意味を持ちます)

このようにすると、And と Or の優先順位を知らない人にとっても、コードが読みやすくなります。


なお言語仕様的には、And は Or よりも優先される(* や / が、+ や - より優先されるのと同じ)ため、
変更前のコードはパターン1 の動作を意味します。パターン2の動作とはならないことに注意してください。

演算子の優先順位を理解している人の中には、And/Or を交えた複合条件でも括弧をあえて
表記しないという人もいますが、それはあまり良いコードではありません。プログラマが
どちらの意図で書いたのかを明確にするため、括弧を併用した方が望ましいです。

編集 削除
ちき  2012-06-16 13:01:05  No: 143336  IP: 192.*.*.*

返事くれたかたありがとうございました!!

魔界の魔界の仮面弁士さまへ

> のような内容です。
そもそもの設問に無理がありますし、「フラグ」および変数 flg の意図も読み取れません。

この場合の flg とは、なにを管理する値なのでしょうか?

提示されたコードでは、初期値 0 に対して、各種条件で 0 をセットしてますが、
それってなにもしなくても同じことですよね。質問の意図が読み取れませんでした。

→ごめんなさい。
完全に書き間違えました。
フラグは編集しないときにfig = 1にして
下のifで上記の条件にあてはまったときは、編集をしないということにつかっています。

皆様が回答して下さったので、本当の使用を載せますね。
実はこの上でもう一つ判定をしています。


■仕様
①a = eなら以下の処理を行う
以下の条件にあてはまる場合は編集不可
②a = 1  かつ  b ≠ 1  かつ b≠2  かつ  b ≠ 3
③a = 3 または a = 4 かつ  c ≠ 2  かつ c ≠ 3   かつ  b = 4
④a = 5 または a = 6 かつ b = 5  または b = 6  または b = 7
  
■コーディング

Dim flg as integer = 0

①If a = e then
② If a = 1 AndAlso b <> 1 AndAlso  b <> 2 AndAlso b = 3 then
     flg = 1
③  Elseif a = 3 OrElse a = 4 AndAlso  c <> 2 AndAlse c <> 3 AndAlso b = 4 then
     flg = 1 
④  Elseif a = 5 OrElse a = 6 AndAlse b = 5 OrElse b = 6 OrElse b = 7
     flg = 1
  End if

End if


⑤If flg = 0 then
  '編集処理を行う
End if

というようになっています。

仕様に不備があり申し訳ございませんでした。

編集 削除
ちき  2012-06-16 14:19:09  No: 143337  IP: 192.*.*.*

YuOさんへ

返信ありがとうございました!
仕様に不備があり申し訳ございません。
書き直したのをあげました。

また教えていただいたコードに関して質問させてください。



>個人的には,こういうややこしい場合はメソッドに切り出します。

実は一番最初のIF a = b thenはメソッドに切り出しています。
処理内容としてはあるテーブルのレコードのフィールドとaがマッチする場合編集処理を行うという内容です。

イメージでいうと
if match()(仮のメソッド名) then
といった感じです。

■全体的な仕様
あるテーブルのデータを取得し、そのデータを編集する必要があるかどうかの判定をして、
編集するものがある場合は編集するといった感じです。
(本当はまだ続きがありますが、取り合えずここまでにさせてください)

現在のイメージ
for 1 to 30 
   if match() then
     'セレクト以下の処理
   end if

next


以下のようにメソッドを使う場合は、

'編集する場合はTrue
if IsEdit() then
なのはわかります。

>想像するに,こんな条件なのでしょうか。
>Private Function IsEdit () As Boolean ' 編集「する」場合にTrueを返す。メソッド名は肯定的に付ける (Boolean型プロパティからの類推)。
>    If a = b Then Return True
>    Select Case b
>        Case 1
>            Return c <> 2 AndAlso c <> 3 AndAlso c <> 4
>        Case 2, 3
>            Return d <> 1 AndAlso d <> 2 AndAlso d <> 5
>        Case 4, 5
>            Return c <> 6 AndAlso c <> 7 AndAlso c <> 8
>    End Select
>    Return True
>End Function

Case に合致した場合のReturnのときは何が返ってくるのか理解できませんでした。
理解力がなくて申し訳ございませんが、教えてください。

編集 削除
YuO  2012-06-17 01:23:15  No: 143338  IP: 192.*.*.*

> Case に合致した場合のReturnのときは何が返ってくるのか理解できませんでした。

単純に式の値であるTrue/Falseをそのまま返しているだけです。


条件式はTrueまたはFalseを値として持ちます。
また,AndAlsoやOrElseも同じくTrueまたはFalseを値として持ちます。

例えば,
>             Return c <> 2 AndAlso c <> 3 AndAlso c <> 4
は,
If c <> 2 AndAlso c <> 3 AndAlso c <> 4 Then Return True Else Return False
と同じです。
このIf文では,Ifの条件式の値と同じものをReturnしているので,If文自体が不要となります。

編集 削除
ちき  2012-06-17 20:08:15  No: 143339  IP: 192.*.*.*

YuOさん

返信ありがとうございます。



>単純に式の値であるTrue/Falseをそのまま返しているだけです。


>条件式はTrueまたはFalseを値として持ちます。
>また,AndAlsoやOrElseも同じくTrueまたはFalseを値として持ちます。

>例えば,
>             Return c <> 2 AndAlso c <> 3 AndAlso c <> 4
>は,
>If c <> 2 AndAlso c <> 3 AndAlso c <> 4 Then Return True Else Return False
>と同じです。
>このIf文では,Ifの条件式の値と同じものをReturnしているので,If文自体が不要となります。

なるほど、 Return c <> 2 AndAlso c <> 3 AndAlso c <> 4
については理解でしきました!!
ありがとうございました。

以下のように書いてみたのですが、一つ問題が・・・。
  Return c <> 2 AndAlso c <> 3 AndAlso c <> 4  のときは  ruturn でfalse が返ってしまいます。
  できたら編集不可のときはfalse で編集可のときは true  を返したいのですが、
どう返したらいいかわかりません。

できたら教えていただけると助かります。
すみませんが、よろしくおねがいします。  


    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim a As String = "2624000"
        Dim kari As String = "2624000"


        If a = kari Then
            If IsEdit() = False Then
                a = "26"
            End If

        End If


    End Sub



    '編集条件判定




    Private Function IsEdit() As Boolean


        Dim b As String = "2624000"
        Dim c As String = "008"
        Dim d As String = "2"


        IsEdit = True


        Select Case b

            Case "2624000"

                Return c <> "008" AndAlso c <> "007" AndAlsoc <> "009"

            Case "2611000", "2622000"

                Return d <> "2" AndAlso d <> "4" AndAlso c = "306"

            Case "2626001", "2550000"

                Return c = "306" OrElse c = "358" OrElse c = "378"

            Case Else
                Return False

        End Select

    End Function

End Class

編集 削除
魔界の仮面弁士  2012-06-17 21:14:08  No: 143340  IP: 192.*.*.*

> できたら編集不可のときはfalse で編集可のときは true
『Return c <> 2 AndAlso c <> 3 AndAlso c <> 4』を逆にするだけなら
「Return Not (c <> 2 AndAlso c <> 3 AndAlso c <> 4)」ですね。
「Return c = 2 OrElse c = 3 OrElse c = 4」とも書けますが。


> If IsEdit() = False Then

私は、CanEdit などと記述する派です。
後に続く単語によって、「Can + 動詞」「Is + 形容詞」などと使い分け。

編集 削除
ちき  2012-06-17 21:58:33  No: 143341  IP: 192.*.*.*

魔界の仮面弁士さん

お早い返信ありがとうございます。

>『Return c <> 2 AndAlso c <> 3 AndAlso c <> 4』を逆にするだけなら
>「Return Not (c <> 2 AndAlso c <> 3 AndAlso c <> 4)」ですね。
>「Return c = 2 OrElse c = 3 OrElse c = 4」とも書けますが。

二つの書き方があるのですね。
どっちを使うかは自分の好みということでよろしいのでしょうか?
できたらNotよりは
Return c = 2 OrElse c = 3 OrElse c = 4を使いたと思っています。



> If IsEdit() = False Then

>私は、CanEdit などと記述する派です。
>後に続く単語によって、「Can + 動詞」「Is + 形容詞」などと使い分け。

についてですが、関数名のつけたの問題ととらえてよろしいのでしょうか?

If CanEdit() then

 Private Function CanEdit() As Boolean

にしたほうがいいということでしょうか?

お手数ですが、返信よろしくお願いいたします。

編集 削除
ちき  2012-06-17 22:32:23  No: 143342  IP: 192.*.*.*

>『Return c <> 2 AndAlso c <> 3 AndAlso c <> 4』を逆にするだけなら
>「Return Not (c <> 2 AndAlso c <> 3 AndAlso c <> 4)」ですね。
>「Return c = 2 OrElse c = 3 OrElse c = 4」とも書けますが。

二つの書き方があるのですね。
どっちを使うかは自分の好みということでよろしいのでしょうか?
できたらNotよりは
Return c = 2 OrElse c = 3 OrElse c = 4を使いたと思っています。



と書いてしまいましたが、意味が違うことに今きづきました。

やりたいことは、
isEditないでcaseにあてはまったら、falseを返す
あてなまらなかったら、Tureを返すといったことです。

ご指導よろしくお願いします。

   Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim a As String = "2624000"
        Dim kari As String = "2624000"

         If a = kari Then
            If IsEdit() = False Then  →編集可の場合は If IsEdit() then

                a = "26"
            End If

        End If
End Sub



    '編集条件判定
 Private Function IsEdit() As Boolean


        Dim b As String = "2624000"
        Dim c As String = "008"
        Dim d As String = "2"


       

         Select Case b

            Case "2624000"

                Return c <> "008" AndAlso c <> "007" AndAlsoc <> "009"  →条件にあてはまったらfalseを返す

            Case "2611000", "2622000"

                Return d <> "2" AndAlso d <> "4" AndAlso c = "306"  →条件にあてはまったらfalseを返す

            Case "2626001", "2550000"

                Return c = "306" OrElse c = "358" OrElse c = "378"  →条件にあてはまったらfalseを返す

            Case Else
                Return False  それ以外だったらtrueを返す。

        End Select

    End Function

End Class

編集 削除
魔界の仮面弁士  2012-06-18 03:05:06  No: 143343  IP: 192.*.*.*

> 二つの書き方があるのですね。

「Not (A AndAlso B)」は、常に「Not A OrElse Not B」と同義です。
「Not (A OrElse B)」は、常に「Not A AndAlso Not B」と同義です。

※上記は ド・モルガンの法則 と呼ばれています。


> Case "2624000"
>     Return c <> "008" AndAlso c <> "007" AndAlso c <> "009"  →条件にあてはまったらfalseを返す

上記コードは、Case "2624000" において、
  「c が、"008" でも "007" でも "009" でもない」ときに True
  「c が、"008"、"007"、"009" のいずれか」ならば False
を返す様になっていますね。

この結果を逆にして
  「c が、"008" でも "007" でも "009" でもない」ときに False、
  「c が、"008"、"007"、"009" のいずれか」ならば True
としたいのであれば、単純に Not で囲めば OK です。

すなわち、先のコードに書いたように
  Return Not (c <> "008" AndAlso c <> "007" AndAlso c <> "009")
になるということです。あるいは、ここにさらにド・モルガンの法則を適用して
  Return c = "008" OrElse c = "007" OrElse c = "009"
と書くこともできます。


> 関数名のつけたの問題ととらえてよろしいのでしょうか?
はい、関数名の話です。
動作上はどちらでも問題ありませんし、さほど深い意味はありません。

Edit が動詞だとしたら、be動詞(Is) + Edit は不自然かな、と感じただけです。
そのうえで、編集可能か不可能かを返すなら、CanEdit あたりが妥当かな、と。


なお、Boolean 型を返す変数やメソッド(関数)は、しばしば

「Is + 形容詞」「Is + 名詞」…例:IsNumeric、IsNothing
「Can + 動詞」…例:CanRead、CanWrite
「Has + 名詞」…例:HasValue、HasErrors
「Has + 過去分詞」例:HasExited
「三単元動詞」…例:Contains、Exists
「三単元動詞 + 名詞」…例:ContainsKey

などが使われます。すべてがそうというわけでは無いですが。
http://www.aerith.net/design/bool-j.html
http://objectclub.jp/community/codingstandard/CodingStdVB.pdf

編集 削除