読者です 読者をやめる 読者になる 読者になる

2 つの Dictionary をひとつにまとめる

両方の Dictionary に同じキーが含まれる場合は、Sum() で足し合わせます。

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

class Program {
    static Dictionary<int, int> Add(Dictionary<int, int> a, Dictionary<int, int> b) {
        return a.Concat(b).GroupBy(e => e.Key, e => e.Value).ToDictionary(e => e.Key, e => e.Sum());
    }

    static void Main() {
        var a = new Dictionary<int, int> {
            { 1, 2 },
            { 2, 3 },
        };

        var b = new Dictionary<int, int> {
            { 0, 1 },
            { 1, 1 },
            { 2, 2 },
            { 5, 0 },
        };

        var c = Add(a, b);
        foreach (var k in c.Keys.OrderBy(e => e)) {
            Console.WriteLine("key:{0} val:{1}", k, c[k]);
        }
    }
}

実行結果です。

key:0 val:1
key:1 val:3
key:2 val:5
key:5 val:0

0,1,0,1,0,1... を繰り返すシーケンス

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

class Program {
    static IEnumerable<int> ZeroOne() {
        int n = 0;
        while (true) {
            yield return n;
            n ^= 1;
        }
    }

    static void Main() {
        Console.WriteLine(string.Join(",", ZeroOne().Take(10)));
        // => 0,1,0,1,0,1,0,1,0,1
    }
}

実行結果です。

0,1,0,1,0,1,0,1,0,1

Pairs 関数

Python

>>> [(i, j) for i in range(3) for j in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

のような各ペアを求める Pairs 関数を作成してみました。

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

public static class Iter {
    static IEnumerable<T[]> Product_1<T>(int p, T[] buf, List<List<T>> pools) {
        if (p == buf.Length) {
            yield return buf;
        }
        else {
            foreach (var e in pools[p]) {
                buf[p] = e;
                foreach (var ret in Product_1(p+1, buf, pools)) {
                    yield return ret;
                }
            }
        }
    }

    public static IEnumerable<T[]> Product<T>(IEnumerable<T> xs, int repeat = 1) {
        var pools = new List<List<T>>(Enumerable.Repeat(xs.ToList(), repeat));
        return Product_1(0, new T[pools.Count], pools);
    }

    public static IEnumerable<T[]> Product<T>(IEnumerable<T> xs, IEnumerable<T> ys, int repeat = 1) {
        var ls = new List<List<T>> { xs.ToList(), ys.ToList() };
        var pools = new List<List<T>>(Enumerable.Repeat(ls, repeat).SelectMany(e => e));
        return Product_1(0, new T[pools.Count], pools);
    }

    public static IEnumerable<U> Pairs<T, U>(IEnumerable<T> xs, IEnumerable<T> ys, Func<T, T, U> fn) {
        foreach (var e in Product(xs, ys)) {
            var cs = e.ToArray();
            yield return fn(cs[0], cs[1]);
        }
    }
}

class Program {
    static void Main() {
        var xs = new[] { 0, 1, 2 };
        var ys = Iter.Pairs(xs, xs, (a, b) => Tuple.Create(a, b));
        Console.WriteLine(string.Join(" ", ys));
        // => (0, 0) (0, 1) (0, 2) (1, 0) (1, 1) (1, 2) (2, 0) (2, 1) (2, 2)
    }
}

Product を経由せずに、foreach で 2 重ループを回すほうが簡単ですが、Product の応用を考えていて Pairs を作れることが分かったので作ってみました。

リンク

Array.Clear() で 2 次元配列をクリアする

Array.Clear メソッドは、1 次元配列だけでなく、2 次元配列もクリアすることが出来ます。

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

class Program {
    static void Display(int[,] ary) {
        for (int i = 0; i < ary.GetLength(0); i++) {
            for (int j = 0; j < ary.GetLength(1); j++) {
                Console.Write("{0} ", ary[i, j]);
            }
            Console.WriteLine();
        }
        Console.WriteLine();
    }

    static void Main() {
        var ary = new int[,] {
            { 1, 2, 3 },
            { 4, 5, 6 },
        };

        Display(ary); // 1 2 3
                      // 4 5 6

        Array.Clear(ary, 1, ary.Length - 1); // ary[0, 0] 以外をクリア
        Display(ary); // 1 0 0
                      // 0 0 0

        Array.Clear(ary, 0, ary.Length); // 全ての要素をクリア
        Display(ary); // 0 0 0
                      // 0 0 0
    }
}

実行結果です。

1 2 3
4 5 6

1 0 0
0 0 0

0 0 0
0 0 0

リンク

Array.Clear メソッド (Array, Int32, Int32) (System)

Conditional 属性の練習

using System;
using System.Diagnostics;

class Program {
    [Conditional("TEST")]
    static void Foo() {
        Console.WriteLine("FOO!");
    }

    static void Main() {
        Console.WriteLine("BEGIN");
        Foo();
        Console.WriteLine("END");
    }
}

実行結果です。

$ mcs -define:TEST a.cs && mono a.exe
BEGIN
FOO!
END
$ mcs a.cs && mono a.exe
BEGIN
END

リンク

Type からインスタンスを生成する

using System;

class Foo {
    public void Say() {
        Console.WriteLine("Foo!");
    }
}

class Bar {
    public Bar(int n, string s) {
        Console.WriteLine("n:{0} s:{1}", n, s);
    }

    public void Say() {
        Console.WriteLine("Bar!");
    }
}

class Program {
    static void Main() {
        var foo = (Foo)Activator.CreateInstance(typeof(Foo));
        foo.Say(); // Foo!

        Type barType = typeof(Bar); // typeof() は Type 型を返す
        var args = new object[] { 123, "bar" }; // Bar のコンストラクタ引数に渡す値
        var bar = (Bar)Activator.CreateInstance(barType, args);
        bar.Say(); // Bar!
    }
}

実行結果です。

Foo!
n:123 s:bar
Bar!

参考

SEND + MORE = MONEY

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

class Program {
    static int ToInt(string s, int[] map) {
        int x = 0;
        foreach (var c in s) {
            x = 10 * x + map[c];
            if (x == 0 && s.Length > 1) return -1; // leading zero
        }
        return x;
    }

    static void Solve_1(int p, char[] cs, int used, int[] map, string[] ss) {
        if (p == cs.Length) {
            var a = ss.Take(ss.Length - 1).Select(e => ToInt(e, map));
            if (a.Contains(-1)) return; // 不正な変換結果

            int b = ToInt(ss.Last(), map);
            if (a.Sum() == b) {
                Console.WriteLine("{0} = {1}", string.Join(" + ", ss.Take(ss.Length - 1)), ss.Last());
                Console.WriteLine("{0} = {1}", string.Join(" + ", a), b);
            }
            return;
        }

        for (int i = 0; i < 10; i++) {
            if ((used & (1 << i)) != 0) continue;

            map[cs[p]] = i; // cs[p] に i を割り当てる
            Solve_1(p + 1, cs, used | (1 << i), map, ss);
        }
    }

    static void Solve(params string[] ss) {
        var cs = new HashSet<char>(ss.SelectMany(e => e)).ToArray();
        if (cs.Length > 10) throw new Exception(); // 10 種類より多いと数字を割り当てられない

        var map = new int[128]; // どの文字にどの数字を割り当てたか
        Solve_1(0, cs, 0, map, ss);
        Console.WriteLine();
    }

    static void Main() {
        Solve("SEND", "MORE", "MONEY");
        Solve("CROSS", "ROADS", "DANGER");
        Solve("SIX", "SEVEN", "SEVEN", "TWENTY");
    }
}

実行結果です。

$ time mono a.exe
SEND + MORE = MONEY
9567 + 1085 = 10652

CROSS + ROADS = DANGER
96233 + 62513 = 158746

SIX + SEVEN + SEVEN = TWENTY
650 + 68782 + 68782 = 138214

mono a.exe  5.38s user 0.03s system 99% cpu 5.419 total

リンク