2重ループをLINQで行う

2つの配列をforeachを使って2重ループする次のコードを、
LINQを使ったコードに書き換えます。

static void Func1()
{
    string[] array1 = { "A", "B", "C" };
    int[] array2 = { 1, 2, 3 };
    var q = new List<string>();

    foreach (var n in array1)
        foreach (var m in array2)
            q.Add($"{n}{m}");

    foreach (var i in q)
        Console.WriteLine(i);
}

実行結果

A1
A2
A3
B1
B2
B3
C1
C2
C3

クエリ構文

クエリ構文は、fromは2回以上使用できます。
fromを2回使って、2重ループと同じ処理ができます。

static void Func2()
{
    string[] array1 = { "A", "B", "C" };
    int[] array2 = { 1, 2, 3 };

    var q =
        from n in array1
        from m in array2
        select $"{n}{m}";

    foreach (var i in q)
        Console.WriteLine(i);
}

メソッド構文

メソッド構文を使用する場合は、SelectManyメソッドを使用します。

static void Func3()
{
    string[] array1 = { "A", "B", "C" };
    int[] array2 = { 1, 2, 3 };

    var q = array1.SelectMany(
        _ => array2,
        (n, m) => $"{n}{m}");

    foreach (var i in q)
        Console.WriteLine(i);
}

Pythonで条件に一致するlist内の要素のインデックスを取得する

条件に一致するlist内の要素を検索して、見つかった要素のインデックスのリストを返すコードです。

def func1(lst, value):
    return [i for i, x in enumerate(lst) if x == value]

リストlstの値の中から変数valueに一致する値を検索して、そのインデックスのリストを返しています。

使用例

lst = [2, 1, 3, 1, 2]
idx = func1(lst, 1)
print(idx) #=> [1, 3]

リストlstの中から、値が1のものを検索して、そのインデックスを変数idxに代入しています。

list.index(x[, start[, end]])

リストのindex()メソッドを使った方法もあります。

listには、インデックスを返すメソッドindex()があります。

list.index(x[, start[, end]])

index()メソッドを使うと次のようなコードになります。

def func2(l, value):
    i = -1
    c = len(l)
    result = []
    while i < c:
        try:
            i = l.index(value, i + 1)
            result.append(i)
        except:
            return result
    return result

速度を比較してみる

最初のenumerateを使ったコードとlist.index()を使ったコードはどちらが早いでしょうか。

試してみました。
ソースコードは最後にあります。

>python test.py 5
func1は6.757836103439331秒かかりました
func2は8.353251934051514秒かかりました
「19994138」件見つかりました。

>python test.py 50
func1は5.679813385009766秒かかりました
func2は2.1373281478881836秒かかりました
「1997806」件見つかりました。

>python test.py 500
func1は6.612039089202881秒かかりました
func2は1.5565226078033447秒かかりました
「199632」件見つかりました。

list内に検索した要素が多いときはlist.index()が遅くなりました。
逆に、少ないときはlist.index()が早くなりました。

enumerateを使ったコードはlistの内容にかかわらず、速度は安定していました。

ソースコード

計測に使用したコードです。

from functools import wraps
import random
import sys
import time

def stop_watch(func):
    '''
    https://qiita.com/hisatoshi/items/7354c76a4412dffc4fd7
    を参考にしました
    '''
    @wraps(func)
    def wrapper(*args, **kargs) :
        start = time.time()
        result = func(*args,**kargs)
        elapsed_time =  time.time() - start
        print(f"{func.__name__}は{elapsed_time}秒かかりました")
        return result
    return wrapper

@stop_watch
def func1(l, value):
    return [i for i, x in enumerate(l) if x == value]

@stop_watch
def func2(l, value):
    i = -1
    c = len(l)
    result = []
    while i < c:
        try:
            i = l.index(value, i + 1)
            result.append(i)
        except:
            return result
    return result

def start(c):
    VALUE = 0
    L = [random.randrange(c) for i in range(100000000)]

    v1 = func1(L, VALUE)
    v2 = func2(L, VALUE)
    assert(v1 == v2)
    print(f'「{len(v1)}」件見つかりました。')

c = int(sys.argv[1])
start(c)

C#のコレクション初期化子とインデックス初期化子

コレクション初期化子

コレクション初期化子は、C# 3.0から使える初期化構文です。

var d = new Dictionary<string, int>
{
    { "太郎", 90},
    { "次郎", 80},
    { "花子", 95},
};

コレクション初期化子はAddメソッドへ変換されます。

上記のコードは、次のコードと同じ意味です。

var tmp = new Dictionary<string, int>();
tmp.Add("太郎", 90);
tmp.Add("次郎", 80);
tmp.Add("花子", 95);
var d = tmp;

インデックス初期化子

インデックス初期化子は、C# 6.0から使える初期化構文です。

var d = new Dictionary<string, int>
{
    ["太郎"] = 90,
    ["次郎"] = 80,
    ["花子"] = 95,
};

インデックス初期化子はインデクサによるアクセスに変換されます。

var tmp = new Dictionary<string, int>();
tmp["太郎"] = 90;
tmp["次郎"] = 80;
tmp["花子"] = 95;
var d = tmp;

そのため、インデクサがあればDictionaryでなくても使用できます。

class Sample
{
    public string this[string key] { get => ""; set { } }
}
var s = new Sample
{
    ["key2"] = "Key2",
    ["key3"] = "Key3",
};

また、プロパティへの代入と一緒に使用できます。

class Sample
{
    public string Key1 { get; set; }
    public string this[string key] { get => ""; set { } }
}

var s = new Sample
{
    Key1 = "key1",
    ["key2"] = "Key2",
    ["key3"] = "Key3",
};

Pythonでランダムな整数を取得する

random.randrange(stop)は0以上stop未満のランダムな整数を返します。

import random

# 0以上10未満のランダムな整数を取得する
n = random.randrange(10)

random.randrange(start, stop)は、start以上stop未満のランダムな整数を取得します。

import random

# 20以上30未満のランダムな整数を取得する
n = random.randrange(20, 30)

次のコードは、10以上20未満のランダムな値を30個持つlistを作成します。

import random

# 10以上20未満のランダムな値を30個持つlistを作成する
l = [random.randrange(10, 20) for i in range(30)]