hotch-potch, Note to self

いろいろ作業記録

言語比較文化~ラムダ式

1.はじめに

プログラム言語ごとの”文化”とも言える構文の違いを比べると、非常に興味深い知見が得られます。

今回は、ラムダ式(言語によってはフィルタ、イテレータと呼称)の書き方をまとめてみました。

2.コード

List型に、独自の構造体Elementを格納します。 その中で、Element.numの値が3の倍数の要素だけ取り出します。

Element型構造体

Element
.num int型
.text string型

List型ダミーデータの中身

index Element.num Element.text
0 1 "item1"
1 2 "item2"
8 9 "item9"
9 10 "item10"

実行例

--- 元データ ---
 > 1 / item1
 > 2 / item2
 > 3 / item3
 > 4 / item4
 > 5 / item5
 > 6 / item6
 > 7 / item7
 > 8 / item8
 > 9 / item9
 > 10 / item10
--- 抽出後データ ---
 > 3 / item3
 > 6 / item6
 > 9 / item9

C Sharp

using System;
using System.Collections.Generic;
using System.Linq;

//要素
public class Element{
    public int num;
    public string text;
}

//サンプルクラス
public class Lambda{
    
    //実行
    public static void Main(){
        //要素のリストに、ダミーデータを追加
        var lists = init();
        
        System.Console.WriteLine("--- 元データ ---");
        foreach(var item in lists)
            System.Console.WriteLine($" > {item.num} / {item.text}");
        
        //ラムダ式
        //Element.numが3の倍数のものだけ抽出
        var lists_filter = lists
        .Where(item => (item.num % 3) == 0)
        .Select(item => item);  
        
        System.Console.WriteLine("--- 抽出後データ ---");
        foreach(var item in lists_filter)
            System.Console.WriteLine($" > {item.num} / {item.text}");
    }
    
    ///テスト用の要素追加
    public static List<Element> init(){

        //要素のリストを生成
        List<Element> lists = new List<Element>();

        foreach(var i in Enumerable.Range(1, 10)){
            //1アイテムずつダミーデータを追加
            var elem = new Element();
            elem.num = i;
            elem.text = $"item{i}";
            lists.Add(elem);
        }
        return(lists);
    }
}

Elixir

# 要素
defmodule Element do
  defstruct num: nil, text: nil
end

# サンプルモジュール
defmodule Lambda do
    
    # 実行
    def main do
        # 要素のリストに、ダミーデータを追加
        lists = init()
        
        IO.puts("--- 元データ ---")
        lists
        |>Enum.each(fn(item) -> IO.puts(" > #{item.num} / #{item.text}") end)
        
        # 抽出
        # Element.numが3の倍数のものだけ抽出
        
        # ●方式1・内包表記 https://elixirschool.com/ja/lessons/basics/comprehensions
        lists_filter = for item <- lists, rem(item.num, 3) == 0, do: item

        # ●方式2・フィルタ https://zenn.dev/koga1020/articles/903d6a6bdde26b
        _lists_filter = Enum.filter(lists, fn item -> rem(item.num, 3) == 0 end)
        
        IO.puts("--- 抽出後データ ---")
        lists_filter
        |>Enum.each(fn(item) -> IO.puts(" > #{item.num} / #{item.text}") end)
    end

    # パイプで繋いで一気に処理する場合
    def main2 do
        init()
        |>Enum.filter(fn item -> rem(item.num, 3) == 0 end)
        |>IO.inspect
    end

    # テスト用の要素追加
    def init() do
        lists = []
        # 1アイテムずつダミーデータを追加
        lists ++ for i <- 1..10, do: %Element{num: i, text: "item#{i}"}
    end
end

# 各々実行
Lambda.main
Lambda.main2

Go

package main
import "fmt"
import "strconv"

//要素
type Element struct {
   num int
   text string
}

//実行
func main(){
    //要素のリストに、ダミーデータを追加
    lists := initlist()
    
    fmt.Println("--- 元データ ---")
    for _ ,v := range lists {
        fmt.Println("> ", v.num, " / ", v.text )
    }

    //Element.numが3の倍数のものだけ抽出
    lists_filter := []Element{}
    for _ ,v := range lists {
        if (v.num % 3 == 0){
            lists_filter = append(lists_filter, v)
        }
    }
    //filter的な機能はない(forが早い!)らしいので、この書き方
    //https://twitter.com/kinyuka/status/1440892918802173953
    
    fmt.Println("--- 抽出後データ ---")
    for _ ,v := range lists_filter {
        fmt.Println("> ", v.num, " / ", v.text )
    }
}

//テスト用の要素追加
func initlist() []Element {
    
    //要素のリストを生成
    lists := []Element{}
    
    //1アイテムずつダミーデータを追加
    for i := 1; i <= 10; i++{
        elem := new(Element)
        elem.num = i
        elem.text = "item" + strconv.Itoa(i)
        lists = append(lists, *elem)
    }

    return lists
}

Rust

//要素
struct Element { num: u32, text: String }

//実行
fn main(){
    //要素のリストに、ダミーデータを追加
    let lists = init();

    println!("--- 元データ ---");
    //ここでは変数の借用"&"が必要
    //https://blog.foresta.me/posts/rust_ownership/
    for item in &lists {
        println!("{} / {}", item.num, item.text);
    }
    
    //イテレータ
    //https://zenn.dev/mebiusbox/books/22d4c1ed9b0003/viewer/a86937
    //Element.numが3の倍数のものだけ抽出
    let lists_filter = lists.iter().filter(|&item| (item.num % 3) == 0);

    println!("--- 抽出後データ ---");
    for item in lists_filter {
        println!("{} / {}", item.num, item.text);
    }
}

//テスト用の要素追加
fn init() -> Vec::<Element> {
    //要素のリストを生成
    let mut lists = Vec::<Element>::new();

    //1アイテムずつダミーデータを追加
    for i in 1..11 {
        let elem = Element {
            num: i,
            text: String::from(format!("item{}", i)),
        };
        lists.push(elem);
    }
    return(lists);
}

Python

# coding: utf-8

from typing import List

# 要素
class Element:
    num : int
    text : str

# 実行    
def main():
    # 要素のリストに、ダミーデータを追加
    lists = init()

    print("--- 元データ ---")
    for item in lists:
        print(f' > {item.num} / {item.text}')

    # ラムダ式
    # https://note.nkmk.me/python-filter-usage/
    # Element.numが3の倍数のものだけ抽出
    lists_filter = \
        list(
            filter(
                lambda item: item.num % 3 == 0, lists
                )
        )

    print("--- 抽出後データ ---")
    for item in lists_filter:
        print(f' > {item.num} / {item.text}')

# テスト用の要素追加
def init() -> List[Element]:

    lists: List[Element] = [];

    # 1アイテムずつダミーデータを追加
    for i in range(1, 10):
        elem = Element();
        elem.num = i;
        elem.text = f"item{i}";
        lists.append(elem);
    
    return lists

if __name__ == "__main__":
    main()