61454


python初心者です。

[code]

    A = [['apple','Apple'],
    　　　['APPLE','Apple'],
    　　　['APPLE','APPLE'],
    　　　['banana','Banana'],
    　　　['ORANGE','orange'],
    　　　['grape','Grape'],
    　　　['GRAPE','Grape']]
    
[/code]

Aのような二次元配列のリストがあります。行いたい処理は以下の通りです。

①０番目の要素を比較して、大文字と小文字の違いのみであれば同じとみなし（この場合は'apple'='APPLE'）、その要素を含むリストを丸ごと削除する  
②ただし①に当てはまっても、１番目の要素が異なれば削除しない（最後の要素は'Apple' !=
'APPLE'なので、上の２つとは異なるとみなし、削除しない）  
③残った要素を表示

[code]

    result = [['banana','Banana'],['ORANGE','orange']]
    
[/code]

このような結果が得られることを期待しています。  
どのような処理をしたらよいのかご教示お願い致します。


CC BY-SA 4.0
2019-12-15T06:02:50.197
61451
2019-12-15T13:43:12.107
2019-12-15T08:47:03.977
36978
36978
question
python
二次元配列で要素を比較して削除したい


今回のは @metropolis さん、@letrec さんの回答が簡潔ですね。

後から加わった条件を加味すると、私の方では以下の様に考えられます。  
前回の @metropolis さんの itertools.groupby を参考にさせてもらいました。

[code]

    from itertools import groupby
    A = [
        ['APPLE', 'APPLE'],
        ['APPLE', 'Apple'],
        ['ApPlE','aPPLe'],
        ['GRAPE', 'Grape'],
        ['ORANGE', 'orange'],
        ['apple', 'Apple'],
        ['banana', 'Banana'],
        ['grape', 'Grape']
    ]
    
    # ソートの評価方法を1番目:大文字/小文字の区別無し、2番目:区別有りにする
    A.sort(key=lambda x:(x[0].lower(), x[1]))
    result = []
    
    # 1番目の要素でグループ化
    B = groupby(A, key=lambda x:x[0].lower())
    for key1, grp1 in B:
        C = list(grp1)
        if len(C) == 1:
            result.extend(C) # 1番目の要素で単独の物のみ追加
        else:
            # 2番目の要素でグループ化
            D = groupby(C, key=lambda x:x[1])
            for key2, grp2 in D:
                E = list(grp2)
                if len(E) == 1:
                    result.extend(E) # 2番目の要素で単独の物のみ追加
    
    print(result)
    
[/code]

* * *

以下は元々の条件での回答です。

一応こちらは前回の[記事](https://ja.stackoverflow.com/q/61277/26370)の応用で、`sort()`の評価方法を大文字/小文字の区別がなくなるように変更する形になります。  
ただし、初期のデータのリスト内での出現順番は保持できなくなります。

大文字/小文字の区別を無視する方法は、この記事 [How do I do a case-insensitive string
comparison?](https://stackoverflow.com/q/319426/9014308)
の応用で、データがASCIIの範囲内なら`lower()`で、Unicodeの範囲なら`import
unicodedata`して`unicodedata.normalize("NFKD", text.casefold())`を使います。

( **注：** コメントでデータがソートされていると追記されましたが、大文字/小文字の区別なく同じ文字列が並ぶならこちら側のソート処理は不要になります)

[code]

    A = [['apple','Apple'],['APPLE','Apple'],['banana','Banana'],['ORANGE','orange'],['grape','Grape'],['GRAPE','Grape']]
    
    A.sort(key=lambda x:x[0].lower()) # ソートの評価方法を大文字/小文字の区別無しにする
    # 元データが大文字/小文字の区別無しにソート済みなら上記は不要
    
    result = []
    work = []
    prev = A[0][0].lower() # あらかじめ最初のデータを変換しておく
    work.append(A[0])
    
    for i in range(1,len(A)):
        current = A[i][0].lower() # 処理回数が少なくなるように1回だけ変換
        if prev == current:       # 各行の1つ目のデータが同じ時
            work = []                 # 同じものがあるのでデータは捨てる
        else:                     # 各行の1つ目のデータが変わった時
            prev = current            # 直前データを更新
            if work:                  # 格納したデータがあるなら結果へ追加
                result.extend(work)
                work = []             # 作業リストはいったんクリア
    
            work.append(A[i])         # 新しいデータをリストに格納
    
    if work:                # ループ終了後にデータが残っていたら結果へ追加
        result.extend(work)
    
[/code]


CC BY-SA 4.0
2019-12-15T06:33:23.827
61452
2019-12-15T10:19:10.583
2019-12-15T10:19:10.583
26370
26370
61451
answer


※ 条件②が追加されたため回答内容を全面変更

辞書(dict)を使って以下の様に書いてみました。

[code]

    from collections import defaultdict
    
    A = [
      ['apple','Apple'],
      ['APPLE','Apple'],
      ['APPLE','APPLE'],
      ['ApPlE','aPPLe'], ## added for testing, outputed to result
      ['banana','Banana'],
      ['ORANGE','orange'],
      ['grape','Grape'],
      ['GRAPE','Grape']
    ]
    
    dic = defaultdict(lambda: defaultdict(list))
    for v in A:
      dic[v[0].lower()][v[1]] += [v]
    
    print([u[0] for v in dic.values() for u in v.values() if len(u) == 1])
    ## =>
    [['APPLE', 'APPLE'], ['ApPlE', 'aPPLe'], ['banana', 'Banana'], ['ORANGE', 'orange']]
    
[/code]

**追記**

`pandas` を使うと以下の様に書けます。

[code]

    import pandas as pd
    
    df = pd.DataFrame(A)
    lst = df.assign(x=df[0].str.lower())\
            .drop_duplicates(subset=[1, 'x'], keep=False)\
            .drop('x', axis=1).values.tolist()
    
    print(lst)
    ## =>
    [['APPLE', 'APPLE'], ['ApPlE', 'aPPLe'], ['banana', 'Banana'], ['ORANGE', 'orange']]
    
[/code]


CC BY-SA 4.0
2019-12-15T08:19:36.507
61454
2019-12-15T11:03:09.790
2019-12-15T11:03:09.790
61451
answer


前後の要素と比較して、第1要素が一致しなければ結果に追加すると考えれば次のように書けますね。以下のコードでは、第1要素として空文字列が現れることはないという仮定を置いて、それを[番兵](https://ja.wikipedia.org/wiki/%E7%95%AA%E5%85%B5)として使っています。

[code]

    A = [['apple', 'Apple'],
         ['APPLE', 'Apple'],
         ['banana', 'Banana'],
         ['ORANGE', 'orange'],
         ['grape', 'Grape'],
         ['GRAPE', 'Grape'],
         ['APPLE', 'APPLE']]
    
    A = [[""]] + A + [[""]]
    
    B = [
        A[i] for i in range(1, len(A) - 1)
        if A[i][0].lower() != A[i - 1][0].lower() and A[i][0].lower() != A[i + 1][0].lower()
    ]
    
    print(B)
    
    
[/code]

実行結果

[code]

    [['banana', 'Banana'], ['ORANGE', 'orange'], ['APPLE', 'APPLE']]
    
[/code]

> 元のリストAから削除した要素はどのような処理をしたら見られますか？

(本来コメントで質問するのは避けるべきで、しかも元の質問に無い内容であれば、新たに投稿するべきだとは思いますが・・・)

`if`で否定の条件を与えてやればよいです。（以下では条件判定の部分を再利用するために関数化しました。）

[code]

    A = [[""]] + A + [[""]]
    
    
    def pred(A, i):
        return A[i][0].lower() != A[i - 1][0].lower() and A[i][0].lower() != A[i + 1][0].lower()
    
    
    B = [A[i] for i in range(1, len(A) - 1) if pred(A, i)]
    
    C = [A[i] for i in range(1, len(A) - 1) if not pred(A, i)]
    
    print(B)
    print(C)
    
    
[/code]


CC BY-SA 4.0
2019-12-15T08:48:53.250
61456
2019-12-15T13:43:12.107
2019-12-15T13:43:12.107
13199
13199
61451
answer