2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「filterM で powerset」をC#らしく

Last updated at Posted at 2012-08-16

(2025/6)
さすがにコード例が古いので、コレクション式を使って書き換え。

filterM は.NETにはないので、無理に実装を合わせる必要はない。
特に、Func<int, IEnumerable<bool>> pred = x => new[] { true, false }; の部分をラムダ式にする意味はない。
やってることは直積なんだから、[true, false] でいい。

List<int> xs = [1, 2, 3, 4];
List<List<int>> ys = PowerSet(xs);

foreach (var l in ys)
{
    Console.WriteLine($"[{string.Join(", ", l)}]");
}

List<List<T>> PowerSet<T>(List<T> xs)
{
    List<T> newAdd(List<T> l, T x) => [.. l, x];
    List<bool> flags = [true, false];
    List<List<T>> folder(List<List<T>> acc, T x)
    {
        var col =
            from f in flags
            from l in acc
            select f ? newAdd(l, x) : l;
        return [.. col];
    }
    List<List<T>> state = [[]];
    return xs.Aggregate(state, folder);
}

前回の 『「filterM で powerset」をC#に翻訳』はHaskellからの翻訳なのでC#的にいろいろ無理があった。特に再帰のところ。
熟練した C# 使いは再帰を書かない? その通り。ではどうするか。Aggregateを使う。

Program.cs
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        var array = new[] { 1, 2, 3, 4, 5 };
        Func<int, IEnumerable<bool>> pred = x => new[] { true, false };

        foreach (var l in array.WhereMany(pred))
        {
            Console.WriteLine(l.ToStringEx());
        }
    }
}

public static class EnumerableEx
{
    public static IEnumerable<IEnumerable<T>> WhereMany<T>(
        this IEnumerable<T> source,
        Func<T, IEnumerable<bool>> predicates)
    {
        return source.Aggregate(
            Enumerable.Repeat(new LinkedList<T>(), 1),
            (acc, x) => acc.SelectMany(q => Accumulate(q, x, predicates))
        );
    }

    private static IEnumerable<LinkedList<T>> Accumulate<T>(
        LinkedList<T> q,
        T x,
        Func<T, IEnumerable<bool>> predicates)
    {
        foreach(var b in predicates(x))
        {
            if (b)
            {
                q.AddLast(x);
                yield return q;
                q.RemoveLast();
            }
            else
            {
                yield return q;
            }
        }
    }

    public static string ToStringEx<T>(this IEnumerable<T> source)
    {
        var strings = source.Select(x => x.ToString());
        return "[" + string.Join(", ", strings) + "]";
    }
}
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?