

CSV形式のファイルに対して、`◯◯ がある行` and `any()内のどれかの数字があるもの` というようにしたいのだが、`and
の前の条件で当てはまるもののみ`、または `◯◯` and `any内の最初の数字だけが該当するもの` というようなコードでしか作成できなかった。

"◯◯" があり 且つ "any内のどれか数字がある行" を探すにはどうしたらいいでしょうか？  
おそらくor の条件が反映されてません。

[code]

    if (("◯◯" in line) and (any(["8847450" or "3625014" or "3625037" or "8831472"])in line)):
    
[/code]

* * *

StackOverflowに投稿するのが初めてでコードの質問の仕方も全然わからないものです。  
医療機関のためあまり情報は出さないほうが良いかと思っておりましたが程々出します。

orという条件を反映させたいが反映されない。  
イメージとしては、SYがある行 且つ その行に
AかBかCかDかEの病名がある患者番号を出力するというのが目的です。自分ではorの使い方がまちがっているのではと思ってます。

[code]

    if ("SY") and ("A"or"B"or "C"or"D"or "E")in line:
    
[/code]

any や 下記のように試しましたが、SY行がある患者番号がSYがある数だけ出力されるだけでした。

[code]

    if "SY"in line and ("8847450"or"3625014"or "3625037"or"8831472"or
     "8847490"or"8849662"or"8837631"or"8837585"or"8842213"or"8841636"or"8830978"
     or"8840886"or"8840626"or"3627007"or"3671002"or"8833933"
     or"3623046"or"8840647"or"8845932"or"8841160"or"8847607"or"8847668"or"8849687"
     or"8840659"or"8840661"or"8849884"or"8846886"or"8842298"
     in line):
    
[/code]

* * *

### コードの全体

[code]

    from os import O_EXLOCK
    import pandas as pd
    import numpy as np
    import csv
    
    # データセットの読み込み
    #f = pd.read_csv('RECEIPTC.UKE', 'r', encoding="shift-jis")
    f=open("/Users/RECEIPTC.UKE", encoding="shift-jis")
    #'utf-8'
    
    ############################################################################
                                                                               #
                            #診療                                              #
    ############################################################################
    #if SY（病名）行　　に000000000がある
    #if "SI"(診療行為）行　and"00000000"がある
    
    """"""""""""""""""""""""""""""""""""""""""
    #自発蛍光
    """"""""""""""""""""""""""""""""""""""""""
    line_RE = False
    line_SY = False
    line_SI = False
    
    for line in f:
        # REが出てくるたびに患者名を格納、初期化
        if 'RE' in line:
            name = line.split(',')[13]
            line_RE = True
            line_SY = False
            line_SI = False
    
        #if SY2（病名）行　　に  等がある      
        if ("SY") and ("8847450"or"3625014"or "3625037"or"8831472"or
        "8847490"or"8849662"or"8837631"or"8837585"or"8842213"or"8841636"or"8830978"
        or"8840886"or"8840626"or"3627007"or"3671002"or"8833933"
        or"3623046"or"8840647"or"8845932"or"8841160"or"8847607"or"8847668"or"8849687"
        or"8840659"or"8840661"or"8849884"or"8846886"or"8842298")in line:
            line_SY  = True  # SYの該当あり判定
            print(name) 
        #自発蛍光　　160199310
        if("SI" and "160199310") in line:
            line_SI = True  # SIの該当あり判定
            #print(name) 
        """"""""""""""""""""""""
        #1879  4699 1221 4213 4687 3190 2982
        #4125 3782 3189 4161 3128
        """"""""""""""""""""""""
        if not (line_SY)  and line_SI :
            #print(name)  # 患者名出力
            """"""""""""""""""""""""
            #1879  4699 1221 4213 4687 3190 2982
            #4125 3782 3189 4161 3128
            """"""""""""""""""""""""
            line_RE = False
            line_SY = False
            line_SI = False
            # 初期化
        #break (breakがあると何も出てこなくなる)
    
[/code]

* * *

# 追記

2個あります 2個目は追加となります

### 1点目

@oriri さんのアドバイスを元にコードを編集したのですが  
下記コードにて 同じ患者番号が出るのは 該当 のid_list 内の番号に当てはまる番号が２個あるので患者番号も２個でるのでしょうか？  
例えば 「 > 」 の部分なのですが 2344は 病名（SY行に含まれている数字）に 8831472 が2個ありました（病名をつける際に、右 左等
修飾コード＋病名になるためです 例えば 右という意味の数字、8831472 や 左という意味の数字、8831472 になるため 一人の該当患者の
SY行複数個の中に 8831472 が2個あることになります そのため出力すると 2344が2個出力されるのでしょうか？  
しかし 2542 は同じ該当病名の数字がありませんでした これは、id_list 内の番号にあてはまるものが2つあるからでしょうか？
例えば"8847450","3625014" があったため等。

[code]

        #if SY2（病名）行　　に  等がある 
    
        id_list = ["8847450","3625014", "3625037","8831472",
        "8847490","8849662","8837631","8837585","8842213","8841636","8830978"
        ,"8840886","8840626","3627007","3671002","8833933"
        ,"3623046","8840647","8845932","8841160","8847607","8847668","8849687"
        ,"8840659","8840661","8849884","8846886","8842298"]
    
        if "SY" in line and any(id in line for id in id_list):
            line_SY  = True  # SYの該当あり判定
            #print(name) 
            #8831472  30件あるが出てこない
            """"""""""""""""""""""""
            #1879
            #3128  3816 4699 3218 2496 4213 4689
            #4687 4626 3870                      >2344 2344 (8831472)
            #                                    >4669 4669 (?)
            #3154 3190 4499 199 3074 2982 4108 
            #                                    >2542 2542 (?)
            #4125 3052 
            #                                    >3879 3879  (#8831472)
            #3782  
            #                                    >3189 3189 (?)
            #4488   
            #                                    >4161 4161  (8834556)
            #2987  3128
            """"""""""""""""""""""""
    
[/code]

### 2点目

同じコードを 例えば 輻輳のパターン、 自発蛍光 のパターンを下記のように続けて書くと  
自発蛍光だけのコードのときは出力されるものが何も出力されない  
break を入れましたが意味がなさそうです

[code]

    ############################################################################
                                                                               #
                            #診療                                              #
    ############################################################################
    
    
    #####◯◯◯◯◯◯◯◯！！！！輻輳◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯◯######
    line_RE = False
    line_SY = False
    line_SI = False
    for line in f:
        # REが出てくるたびに患者名を格納、初期化
        if 'RE' in line:
            name = line.split(',')[13]
            line_RE = True
            line_SY = False
            line_SI = False
    
        #if SY2（病名）行　　に3789001(斜視）等がある       
    
        id_list = ["3789001","3784001", "8831705","8844716",
        "3673004","8847774","3785017","3795003","3795019","8026003","8845049",
        "8845078","8838065","3785007","3785014","3675013"]
    
        if "SY" in line and any(id in line for id in id_list):
            line_SY  = True  # SYの該当あり判定
            #print(name) 
            #4357  4358
            #3784001→5件
            #1827  4338  4321 4341 4357 4319 567 4358 387
        if('SI' and '160083810') in line:
            line_SI = True  # SIの該当あり判定
            #print(name) 
            #4338  4321
            #4341  4357 4319  4358 387
            
            #if "SI"(診療行為）行　and"160083810"（輻輳）がある
    
        if not (line_SY)  and line_SI :
            #print(name)  # 患者名出力
            #4338  4321  4341 4319  387
            line_RE = False
            line_SY = False
            line_SI = False
            # 初期化
        break         
        
     
    """"""""""""""""""""""""""""""""""""""""""
    #自発蛍光
    """"""""""""""""""""""""""""""""""""""""""
    line_RE = False
    line_SY = False
    line_SI = False
    
    for line in f:
        # REが出てくるたびに患者名を格納、初期化
        if 'RE' in line:
            name = line.split(',')[13]
            line_RE = True
            line_SY = False
            line_SI = False
    
        
        
        #if SY2（病名）行　　に  等がある 
    
        id_list = ["8847450","3625014", "3625037","8831472",
        "8847490","8849662","8837631","8837585","8842213","8841636","8830978"
        ,"8840886","8840626","3627007","3671002","8833933"
        ,"3623046","8840647","8845932","8841160","8847607","8847668","8849687"
        ,"8840659","8840661","8849884","8846886","8842298"]
    
        if "SY" in line and any(id in line for id in id_list):
            line_SY  = True  # SYの該当あり判定
            #print(name) 
            #8831472  30件あるが出てこない
            """"""""""""""""""""""""
            #1879
            #3128  3816 4699 3218 2496 4213 4689
            #4687 4626 3870                      2344 2344 (8831472)
            #                                    4669 4669 (?)
            #3154 3190 4499 199 3074 2982 4108 
            #                                    2542 2542 (?)
            #4125 3052 
            #                                    3879 3879  (#8831472)
            #3782  
            #                                    3189 3189 (?)
            #4488   
            #                                    4161 4161  (8834556)
            #2987  3128
            """"""""""""""""""""""""
        #自発蛍光　　160199310
        if("SI" and "160199310") in line:
            line_SI = True  # SIの該当あり判定
            print(name) 
        """"""""""""""""""""""""
        #1879  4699 1221 4213 4687 3190 2982
        #4125 3782 3189 4161 3128
        """"""""""""""""""""""""
        if not (line_SY)  and line_SI :
            #print(name)  # 患者名出力
            """"""""""""""""""""""""
            #1221のみになった
            """"""""""""""""""""""""
            #1879  4699 1221 4213 4687 3190 2982
            #4125 3782 3189 4161 3128
            """"""""""""""""""""""""
            line_RE = False
            line_SY = False
            line_SI = False
            # 初期化
    
        break 
        # (breakがあると何も出てこなくなる)
    
[/code]


CC BY-SA 4.0
2021-11-26T11:21:52.823
83820
2021-11-28T02:19:08.520
2021-11-28T02:19:08.520
49240
49240
question
python python3
◯◯ and ( or 複数）というような条件で調べたいが、or の条件が反映されない


よく問題を理解できていないだけかもしれませんが、  
Pythonのany()はTrueかFalseを返すと思います。  
（数字の場合は０以外、Booleanの場合はTrueがリストの中に一つでもあればTrueを返します。）

ですので、上記されているコードでは、

[code]

    any(["8847450" or "3625014" or "3625037" or "8831472"]
    
[/code]

この部分はTrueしか返っておらず、結果として

[code]

    if (("◯◯" in line) and　(True in line)):
    
[/code]

となっており、調べたいことに合致していないと思います。

ですので、もし全ての番号がわかっておられるのであれば、  
簡単に

[code]

    OKIDs = ["8847450","3625014","3625037","8831472"]
    if ("◯◯"in line):
      for id in OKIDs:
        if id in line:
          XXXXXX <- ABCDFさんがやりたいこと
    
[/code]

しておけば大丈夫なような気がします。  
ただし、この場合はlineに”88474501”のような似ている数字が存在する場合も条件に引っかかります。

なので、より細かな条件で調べたいのであれば、  
lineの中から、まずは"◯◯"や特定の数字を抜き取ってくる作業を行なった後  
if statementにするのがよいかと思いますよ。


CC BY-SA 4.0
2021-11-26T18:44:17.523
83825
2021-11-27T07:09:30.807
2021-11-27T07:09:30.807
3060
11048
83820
answer


`line`変数が文字列型である場合, `in` 演算は文字列が含まれるかどうかを Boolで返します  
(Bool: 真偽値, True あるいは False)

参考: <https://docs.python.org/ja/3/reference/expressions.html#membership-test-
operations>

`and` 演算子や `or` 演算子も, (たいていは) Boolを取り扱い, 結果も Boolです

参考: <https://docs.python.org/ja/3/reference/expressions.html#boolean-
operations>

このため複数の文字列のいずれかが含まれているかどうかは, ジェネレーター式を使って以下のように記述できます

[code]

    id_list = ["8847450", "3625014", "3625037", "8831472", "8847490",
        "8849662", "8837631", "8837585", "8842213", "8841636", "8830978",
        "8840886", "8840626", "3627007", "3671002", "8833933", "3623046",
        "8840647", "8845932", "8841160", "8847607", "8847668", "8849687",
        "8840659", "8840661", "8849884", "8846886", "8842298"]
    
    line = 'abcd8846886efg'
    if any(id in line for id in id_list):
        pass # いずれかの文字が含まれていた場合, の処理
    
    # 質問の条件判断はこんな感じ
    if "SY" in line and any(id in line for id in id_list):
        pass #
    
[/code]

* * *

pandas使う場合だと, また異なる条件式になります

* * *

#### 少し追記

リスト内包表記を使い, 番号の文字列が含まれるかどうかのリストを得ることができ, 結果の Boolのリストを `any()` で判定可能

[code]

    bool_list = [id in line for id in id_list]
    print(any(bool_list))
    
[/code]

[ジェネレーター式](https://docs.python.org/ja/3.7/reference/expressions.html#generator-
expressions)は, `list`ではなく generatorとして使用するもので, (少し動作異なるけど)今回の場合はどちらも結果は同じ

* * *

#### 追加分: 「自発蛍光」判定

上記にも記したとおり, `and` 演算子や `or` 演算子は(たいてい) Boolを指定するもので, 文字列を指定した場合は 長さ=0
でない限り真となり, この場合演算結果は後に指定されたものが値となり, 意図した判定にはなりません

[code]

    #自発蛍光　　160199310
    #   if("SI" and "160199310") in line:
    # この判定はカッコ内が先に行われ, and演算子と文字列で無駄な演算してしまうだけ
    
    # (たぶん)正しくはこのような if文
    for line in ['SI', '160199310', '160199310SIO']:
        if "SI" in line and "160199310" in line:
            print(line)
    
[/code]

また, `break`文は if文のインデントから外れているので, 無条件に行われます


CC BY-SA 4.0
2021-11-27T11:17:10.617
83834
2021-11-27T14:02:02.627
2021-11-27T14:02:02.627
43025
43025
83820
answer


テストデータがあると確認しやすいかな、と思いまして少し調べてみると以下のサイトにありました。

[ダウンロード情報｜社会保険診療報酬支払基金](https://www.ssk.or.jp/seikyushiharai/rezept/hokenja/download/index.html)

ここから以下のデータをダウンロードしました。

電子レセプトのCSV情報及びレセプト電子データのサンプルデータ

令和2年4月診療分 医科:18件(ZIP:930KB)

中に入っている CSV ファイルを取り出して、ファイル名を `RECEIPTC.UKE` に変更します。Pandas の `read_csv()`
を使用して読み込みます。

[code]

    import pandas as pd
    
    df = pd.read_csv('RECEIPTC.UKE', 'r', encoding="shift-jis")
                             :
    
    pandas.errors.ParserError: Error tokenizing data. C error: Expected 1 fields in line 123, saw 2
    
[/code]

………なんと、エラーが発生してしまいました。原因はカラム数が不揃いなためです。仕方ないので読み方を変えます。

[code]

    import pandas as pd
    
    df = pd.read_csv('RECEIPTC.UKE', sep='\n', header=None, prefix='X', encoding="shift-jis")
    df = df.X0.str.split(',', expand=True).fillna('')
    
    print(df)
    
          0   1  2   3                                                 4   ... 46 47 48 49 50
    0     2   1  0  MN                                         910000041  ...               
    1     1   2  0  IR                                                 1  ...               
    2     1   3  0  RE                                                 9  ...               
    3     1   4  0  HO                                          06132013  ...               
    4     1   5  0  GR                                                09  ...               
    ...  ..  .. ..  ..                                               ...  ... .. .. .. .. ..
    998   2  11  1  EX                                                    ...               
    999   2  12  1  EX                                                    ...               
    1000  2  13  0  RC          Ver00001bd39c87bcce59458fa26da72e53ef72c  ...               
    1001  2  14  1  RC  Ver000017f93222aded463b40f8281c6d95aadcd37d7ca44  ...               
    1002  
    
    [1003 rows x 51 columns]
    
[/code]

> イメージとしては、SYがある行 且つ その行に AかBかCかDかEの病名がある患者番号を出力するというのが目的です。
[code]

    # 識別情報が SY の行数
    print(len(df[df[3]=='SY']))
    242
    
    # 抽出したい傷病情報リスト
    SVs = ("1509003", "8841698", "2500015", "1509003", "8842624")
    
    # 抽出条件式
    condition = (df[3] == 'SY') & (df[4].isin(SVs))
    
    # 抽出(患者番号が何列目にあるのか分からないので全体を表示)
    print(df[condition])
    
    #
         0   1  2   3        4         5  6     7  8   9  ... 
    5    1   6  0  SY  1509003  20151102  1           01  ... 
    6    1   7  0  SY  8841698  20151110  1               ... 
    7    1   8  0  SY  2500015  20151110  1               ... 
    8    1   9  0  SY  1509003  20151217  1  8048     01  ... 
    9    1  10  0  SY  8842624  20151222  1           01  ... 
    310  1   8  0  SY  2500015  20190121  1               ... 
    546  1   8  0  SY  2500015  20190121  1               ... 
    761  1   9  0  SY  8841698  20190801  1               ... 
    806  1  10  0  SY  8842624  20121203  1               ... 
    877  1  21  0  SY  2500015  20190424  1               ... 
    
    [10 rows x 51 columns]
    
[/code]


CC BY-SA 4.0
2021-11-27T12:37:06.290
83835
2021-11-27T12:42:37.083
2021-11-27T12:42:37.083
47127
47127
83820
answer