如何在纯C#和.Net框架中编写anagram生成器

时间:2010-12-10 14:30:35

标签: c# .net c#-4.0 anagram

我想在没有任何外部库(如Google anagram algorithm helper)的帮助下生成给定字符串的anagram输出。

示例:

  

输入字符串=“GOD”

输出列表应如下所示:

  

G O D GO GD OD OG DG DO GOD GDO ODG   OGD DGO DOG

3 个答案:

答案 0 :(得分:4)

在这么多级别上,这种情况变得非常棒。 我向您介绍一个纯LINQ(但不是非常有效)的解决方案。

    static class Program
    {
        static void Main(string[] args)
        {
            var res = "cat".Anagrams();

            foreach (var anagram in res)
                Console.WriteLine(anagram.MergeToStr());
        }

        static IEnumerable<IEnumerable<T>> Anagrams<T>(this IEnumerable<T> collection) where T: IComparable<T>
        {
            var total = collection.Count();

            // provided str "cat" get all subsets c, a, ca, at, etc (really nonefficient)
            var subsets = collection.Permutations()
                .SelectMany(c => Enumerable.Range(1, total).Select(i => c.Take(i)))
                .Distinct(new CollectionComparer<T>());

            return subsets;
        }

        public static IEnumerable<IEnumerable<T>> Permutations<T>(this IEnumerable<T> collection)
        {
            return collection.Count() > 1 
                ?
                    from ch in collection
                    let set = new[] { ch }
                    from permutation in collection.Except(set).Permutations()
                    select set.Union(permutation)
                :
                    new[] { collection };
        }

        public static string MergeToStr(this IEnumerable<char> chars)
        {
            return new string(chars.ToArray());
        }

    }// class

    // cause Distinct implementation is shit
    public class CollectionComparer<T> : IEqualityComparer<IEnumerable<T>> where T: IComparable<T>
    {
        Dictionary<IEnumerable<T>, int> dict = new Dictionary<IEnumerable<T>, int>();

        public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
        {
            if (x.Count() != y.Count())
                return false;
            return x.Zip(y, (xi, yi) => xi.Equals(yi)).All(compareResult => compareResult);
        }

        public int GetHashCode(IEnumerable<T> obj)
        {
            var inDict = dict.Keys.FirstOrDefault(k => Equals(k, obj));
            if (inDict != null)
                return dict[inDict];
            else
            {
                int n = dict.Count;
                dict[obj] = n;
                return n;
            }
        }
    }// class

答案 1 :(得分:0)

为了它的价值,我用Java编写了可以做你想要的方法,而且我理解C#足够相似你可能会毫不费力地阅读代码。 (语法,即。如果你对递归函数不满意,那么可能会给你带来麻烦。)我的用户名是@undefined over this forum thread。要使用代码,您可以循环k值从1到字符串的长度(包括)。或者,您可以生成所有子集(丢弃空集),如this thread中所述,然后从那里获取排列。另一种方法是编写第k个置换函数并使用它。我没有在网上发帖;我使用的那个有点乱,我应该在某个时候重写它。

编辑值得一提的是,我以一种看似简单的方式编写方法,但更高效的方法是使用堆栈,这样就不必创建大量新对象。

答案 2 :(得分:0)

试试这个

public static IEnumerable<string> Permutations(this string text)
{
    return PermutationsImpl(string.Empty, text);
}

private static IEnumerable<string> PermutationsImpl(string start, string text)
{
    if (text.Length <= 1)
        yield return start + text;
    else
    {
        for (int i = 0; i < text.Length; i++)
        {
            text = text[i] +
                    text.Substring(0, i) +
                    text.Substring(i + 1);
            foreach (var s in PermutationsImpl(start +
                text[0], text.Substring(1)))
                yield return s;
        }
    }
}

然后只需使用这种扩展方法

string text = "CAT";
List<string> perms = text.Permutations().ToList();