

2次元配列の要素の削除に困っています。数字の入っていない`[]`の部分を削除したいです。  
よろしくお願いします。

[code]

    list = [[0,1],[],[],[1,0],[],[],[1,1],[1,2],[],[],[]]
    
[/code]


CC BY-SA 3.0
2015-11-11T11:55:26.843
18685
2015-11-12T11:08:16.477
2015-11-11T13:02:04.883
7290
13226
question
python
2次元配列のリストを削除したい


Python2.7

[code]

    >>> list = filter(lambda x: x != [], list)
    >>> list
    [[0, 1], [1, 0], [1, 1], [1, 2]]
    
[/code]


CC BY-SA 3.0
2015-11-11T12:02:08.573
18686
2015-11-11T13:17:58.213
2015-11-11T13:17:58.213
3054
18685
answer


`list`は Python が標準で使っているので、上書きするのは避けた方がよいです。  
（ただの変数ではあるので、分かってやっているなら構わないですが）  
以下では "`li`" としておきます。

追記: Kenji Noguchiさんのコメントを受け、`[]`との比較を止めて、空のシーケンスが False であることを利用したコードにしました。

基本は新しいリストを作りそれに追加していき、出来たら"`li`"をその新しいリストに束縛する形になると思います。

[code]

    li = [[0,1],[],[],[1,0],[],[],[1,1],[1,2],[],[],[]]
    new_li = []
    
    for v in li:
        if v:
            new_li.append(v)
    li = new_li
    
[/code]

内包表記バージョン(argusさんの回答とほぼ同じ事をしています)

[code]

    li = [[0,1],[],[],[1,0],[],[],[1,1],[1,2],[],[],[]]
    
    li = [x for x in li if x]
    
[/code]

新しいリストを作らずやると以下のようにごちゃごちゃしますし、これで性能がよくなる事もないと思います。（メモリが厳しい場合は分かりませんが）

追記: Tatz Sekineさんの回答でリストの末尾から見ていく方法が紹介されています。あちらの方が断然いいです。  
追記: 実行時間を計測しました。長いので別回答にしましたが、要素の削除は思ったよりずっと遅かったです。

[code]

    li = [[0,1],[],[],[1,0],[],[],[1,1],[1,2],[],[],[]]
    
    del_count = 0
    for i in range(len(li)):
        i -= del_count
        if not li[i]:
            del li[i]
            del_count += 1
    
[/code]


CC BY-SA 3.0
2015-11-11T12:37:28.190
18687
2015-11-12T11:08:16.477
2015-11-12T11:08:16.477
3054
3054
18685
answer


Python2.7

[code]

    >>> l=[[0,1],[],[],[1,0],[],[],[1,1],[1,2],[],[],[]]
    >>> filter(None, l)
    [[0, 1], [1, 0], [1, 1], [1, 2]]
    
[/code]


CC BY-SA 3.0
2015-11-11T13:03:38.147
18688
2015-11-11T13:03:38.147
806
18685
answer

[code]

    li=[[0,1],[],[],[1,0],[],[],[1,1],[1,2],[],[],[]]
    li = [x for x in li if x]
    
[/code]

で十分です。  
あとPython3ではfilter()が返すのはイテレータです。


CC BY-SA 3.0
2015-11-11T13:06:51.087
18689
2015-11-11T13:06:51.087
13227
18685
answer


本当に list から要素を削除したいのなら

[code]

    for i in range(len(ll) - 1, -1, -1):
      if not ll[i]:
        del ll[i]
    
[/code]

で出来ます。

ただ、memory
は多少とも節約できるかもしれませんが、要素削除のコストがかかるのであまりメリットは無いかもしれません。他の回答にあるように、リスト内包表記を使って新たな
list を作る方が短く書けますし、より分かりやすいと思います。


CC BY-SA 3.0
2015-11-11T18:00:35.967
18701
2015-11-11T18:00:35.967
2521
18685
answer


方法による速度の違いが気になったので、みなさんの回答やコメントを参考に実行時間を計りました。  
メモリを気にしない場合は、新しいリストを作るほうがよさそうです。

  * by_filter  
実行時間が一番短かいのは、`filter`を使った物でした。

  * by_comprehension  
内包表記は`filter`より少しだけ遅いですが、あまり変わりません。

  * by_loop  
ループで追加していく方法は、`append`が遅いのでしょうか、大分遅いです。

  * by_loop_inplace  
新しいリストを作らず要素を削除していく方法は、さらに極端に遅くなります。  
削除対象（空リスト）がどれだけあるかに、実行時間が大きく左右されます。  
しかし、削除対象が殆どなくとも、`filter`や内包表記よりわずかに遅いようです。

以下は50万要素の1/10が空リストである場合の結果です。

[code]

    $ ./del_empty.py 
             450015 function calls in 29.540 seconds
    
       Ordered by: cumulative time
    
       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
            1   27.775   27.775   27.775   27.775 del_empty.py:16(by_loop_inplace)
            4    0.000    0.000    1.582    0.395 del_empty.py:22(make_list)
            4    1.582    0.395    1.582    0.395 del_empty.py:23(<listcomp>)
            1    0.095    0.095    0.138    0.138 del_empty.py:3(by_loop)
       450000    0.044    0.000    0.044    0.000 {method 'append' of 'list' objects}
            1    0.000    0.000    0.030    0.030 del_empty.py:10(by_comprehension)
            1    0.030    0.030    0.030    0.030 del_empty.py:11(<listcomp>)
            1    0.015    0.015    0.015    0.015 del_empty.py:13(by_filter)
            1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
            1    0.000    0.000    0.000    0.000 {built-in method len}
    
[/code]

del_empty.py  

[code]

    #! /usr/bin/python3
    
    def by_loop(target_list):
        new_list = []
        for v in target_list:
            if v:
                new_list.append(v)
        return new_list
    
    def by_comprehension(target_list):
        return [x for x in target_list if x]
    
    def by_filter(target_list):
        return list(filter(None, target_list))
    
    def by_loop_inplace(target_list):
        for i in range(len(target_list) - 1, -1, -1):
            if not target_list[i]:
                del target_list[i]
        return target_list
    
    def make_list():
        return [[x, 0] if x % 10 else [] for x in range(500000)]
    
    
    if __name__ == "__main__":
        import cProfile
        pr = cProfile.Profile()
        pr.enable()
    
        by_loop(make_list())
        by_comprehension(make_list())
        by_filter(make_list())
        by_loop_inplace(make_list())
    
        pr.disable()
        pr.print_stats(sort="cumtime")
    
[/code]


CC BY-SA 3.0
2015-11-12T11:03:45.710
18735
2015-11-12T11:03:45.710
3054
18685
answer