🧑‍🎓

【覚書】Pythonとリスト内包表記とLINQ

2025/01/25に公開

リスト内包表記とは

for を展開して配列を作る式、みたいな感じ。
C#のLINQ的な感じです。

Pythonなら

na = [v*2 for v in a]

配列aに対して、forの後のvでイテレーション保存して、forの前のv*2の値が戻り値になって、それが配列分繰り返す…。
というところ。

C#なら

na = a.Select(v => v * 2).ToArray();

かな。

Where

制限をかけるときはどうするのか。

C#なら

表題の通り、Whereを使います。

var a = new []
{
    new {id = 1, is_star = true, star = 3},
    new {id = 2, is_star = true, star = 5},
    new {id = 3, is_star = false, star = 0},
    new {id = 4, is_star = true, star = 2},
};
var na = a.Where(v => v.is_star).Select(v => v.star).ToArray();

余談として、C#ではクエリ構文でも書ける。

na = (
    from v in a
    where v.is_star
    select v.star
    ).ToArray();

Pythonなら

後置ifです。

a = [
    {"id": 1, "is_star": True, "star": 3},
    {"id": 2, "is_star": True, "star": 5},
    {"id": 3, "is_star": False, "star": 0},
    {"id": 4, "is_star": True, "star": 2},
]
na = [v["star"] for v in a if v["is_star"]]

2段Select

これが一番書きたかったこと。

C#なら

SelectMany からの。

var a = new[]
{
    new {id = 1, is_avail = true, content = new[] {
        new {id = 100, is_star = true, star = 5},
        new {id = 101, is_star = false, star = 0},
        new {id = 102, is_star = true, star = 1},
        new {id = 103, is_star = true, star = 3},
    }},
    new {id = 2, is_avail = true, content = new[] {
        new {id = 100, is_star = true, star = 4},
        new {id = 101, is_star = false, star = 0},
        new {id = 102, is_star = false, star = 0},
        new {id = 103, is_star = true, star = 2},
    }},
    new {id = 3, is_avail = false, content = new[] {
        new {id = 100, is_star = true, star = 4},
        new {id = 101, is_star = true, star = 2},
        new {id = 102, is_star = false, star = 1},
        new {id = 103, is_star = true, star = 3},
    }},
    new {id = 4, is_avail = true, content = new[] {
        new {id = 100, is_star = true, star = 5},
        new {id = 101, is_star = true, star = 2},
        new {id = 102, is_star = true, star = 1},
        new {id = 103, is_star = false, star = 0},
    }},
};
var na = a
    .Where(v => v.is_avail)
    .SelectMany(v => v.content)
    .Where(v => v.is_star)
    .Select(v => v.star)
    .ToArray();

Pythonなら

なんかとっても変。

a = [
    {"id":1, "is_avail":True, "content": [
        {"id":100, "is_star": True, "star": 5},
        {"id":101, "is_star": False, "star": 0},
        {"id":102, "is_star": True, "star": 1},
        {"id":103, "is_star": True, "star": 3},
    ]},
    {"id":2, "is_avail":True, "content": [
        {"id":100, "is_star": True, "star": 4},
        {"id":101, "is_star": False, "star": 0},
        {"id":102, "is_star": False, "star": 0},
        {"id":103, "is_star": True, "star": 2},
    ]},
    {"id":3, "is_avail":False, "content": [
        {"id":100, "is_star": True, "star": 4},
        {"id":101, "is_star": True, "star": 2},
        {"id":102, "is_star": False, "star": 1},
        {"id":103, "is_star": True, "star": 3},
    ]},
    {"id":4, "is_avail":True, "content": [
        {"id":100, "is_star": True, "star": 5},
        {"id":101, "is_star": True, "star": 2},
        {"id":102, "is_star": True, "star": 1},
        {"id":103, "is_star": False, "star": 0},
    ]},
]
na = [v["star"] for v1 in a if v1["is_avail"] for v in v1["content"] if v["is_star"]]

1ライナーで書けるのは楽しいんだが、読みにくいこと甚だしい。
見方としては、forif のフローがコード通りに並んでいるだけ、になる。

for v1 in a if v1["is_avail"] for v in v1["content"] if v["is_star"]

ここんところは、つまりはこう書くとわかりやすい。

na = []
for v1 in a:
    if v1["is_avail"]:
        for v in v1["content"]:
            if v["is_star"]:
                na.append(v["star"])

:を抜いてずらずら書いてあるだけ。
そして一番中のforループで使用されている変数が一番前に出てきて処理される最終変数になって、[]で配列になる。

この理屈さえ分かっていれば、 何段だろうが恐いもん無し である。

あ、いや、読みにくさが恐い。

Discussion