C# 他对内存分配进行了中介,包括字符串连接,并最终得到了更通用、更快的解决方案

C# 他对内存分配进行了中介,包括字符串连接,并最终得到了更通用、更快的解决方案,c#,regex,algorithm,out-of-memory,C#,Regex,Algorithm,Out Of Memory,为了做到这一点,我需要做出一些艰难的设计决定。我所说的一般函数的签名如下所示 public static IEnumerable<T[]> RepeatingPermutations<T>(this T[] set, int N) 有趣的是,我最近回答了一个有关组合的问题,并意识到算法基本相同 话虽如此,功能如下: public static IEnumerable<T[]> RepeatingPermutations<T>(this T[] s

为了做到这一点,我需要做出一些艰难的设计决定。我所说的一般函数的签名如下所示

public static IEnumerable<T[]> RepeatingPermutations<T>(this T[] set, int N)
有趣的是,我最近回答了一个有关组合的问题,并意识到算法基本相同

话虽如此,功能如下:

public static IEnumerable<T[]> RepeatingPermutations<T>(this T[] set, int N)
{
    var result = new T[N];
    var indices = new int[N];
    for (int pos = 0, index = 0; ;)
    {
        for (; pos < N; pos++, index = 0)
        {
            indices[pos] = index;
            result[pos] = set[index];
        }
        yield return result;
        do
        {
            if (pos == 0) yield break;
            index = indices[--pos] + 1;
        }
        while (index >= set.Length);
    }
}
在哪里

A-来自@juharr的LINQ函数
B1-带字符串的my函数
B2-带char[]的my函数

正如我们所看到的,在内存方面,这两个字符串函数是可比较的。在性能方面,LINQ函数只慢了约2倍,这是一个非常好的结果

正如在这种情况下所预期的那样,非分配函数的性能明显优于两者

更新:根据评论中的要求,以下是上述函数的示例用法(请注意,它们是扩展方法,必须放在您选择的静态类中):

但是,请记住我所做的设计选择,因此如果在调试器中展开
charPermutations
,您将看到一个相同的值(最后一个排列)。使用上面调用
char[]
的整个结果应该是这样的

public static IEnumerable<string> RepeatingPermutations(this string set, int N)
{
    return set.ToCharArray().RepeatingPermutations(N).Select(p => new string(p));
}
from e1 in set
from e2 in set
...
from eN in set
select new [] { e1, e2, .., eN }
var charPermutationList = charSet.RepeatingPermutations(3)
    .Select(p => (char[])p.Clone()).ToList();
实际上,除了上述两种方法之外,还有一种很好的扩展方法:

public static IEnumerable<T[]> Clone<T>(this IEnumerable<T[]> source)
{
    return source.Select(item => (T[])item.Clone());
}

等待您正在尝试对字母表中的所有字母进行排列?假设每个排列的长度为6。。。这是165765600个不同的对象。(在计算器中键入
26P6
)。对于长度为5的排列,这是7893600(在计算器中键入
26P5
)。是的,这正是我目前正在做的。我知道字母表中所有字母的6个字母排列会变得非常庞大,所以我正在尝试找出最聪明的方法。如果你将代码改为使用IEnumerable而不是列表,那么就不需要同时在内存中进行所有排列,你可能想查看Eric Lippert的博客帖子。是的,当时我可以用正则表达式过滤它们,但是使用
q.SelectMany(x=>source,(x,y)=>x+y)是我知道如何生成置换的唯一方法。你能帮我想一想如何做到这一点吗?@Shard我才11年级,而且我绝对不是什么超级酷的数学人,所以我不确定我能帮上什么忙。很抱歉:(这也适用于字母吗?你能解释一下你的代码吗?特别是getPermutation方法。是的,这将为任何输入字符串生成置换。我只是在这里使用了一个数字字符串作为示例。我正在更新代码,并提供更多解释。谢谢!因为我修改了代码,以使用我使用al的示例。)phabet,但我似乎无法让它工作。我的字符串输入是一个字母表,然后我告诉我的代码生成例如3个字母的单词,它创建例如aaa、aab、aac…等等。所以在每个步骤中都使用整个字母表。我在我的帖子中添加了一张图片,以演示我想要的更好。使用您编辑的代码,这是否意味着例如
aaab
不可能?回答很好。特别是在算法和性能分析部分。;)+1您还可以添加一个如何调用char[]函数的示例吗?@Ian很高兴见到您:)谢谢!从过去的好时光开始,数据结构、算法和性能一直是我最喜欢的领域:)@IvanStoev哈哈。。。这里也是……)祝贺你获得了赏金!;)@伊恩·洛尔。是的,我开始学习是因为我对学习更多感兴趣。毕竟我在11年级:)
public IEnumerable<string> getPermutation(string input, string regexp)
{
        Stack<string> left = new Stack<string>();
        Stack<string> acc = new Stack<string>();

        left.Push(input);
        acc.Push("");

        // generate all permutations that match regexp
        while (left.Count > 0)
        {
            string c = left.Pop();
            string r = acc.Pop();

            if(r.Length==input.Length)
            {
                yield return r;
            }
            else
            {
                for(int i=0;i<c.Length;i++)
                {
                    string p = r + c[i];
                    if (Regex.IsMatch(p,regexp)) // continue if we have a potential match
                    {
                        left.Push(c.Substring(0, i) + c.Substring(i + 1));
                        acc.Push(p);
                    }
                }
            }

        }            
}



foreach(var a in getPermutation("123456789", "^3$|^32$|^321"))
{
    if(Regex.IsMatch(a, "32145.67"))
    {
         // found match
    }

}
public static IEnumerable<T[]> RepeatingPermutations<T>(this T[] set, int N)
public static IEnumerable<string> RepeatingPermutations(this string set, int N)
{
    return set.ToCharArray().RepeatingPermutations(N).Select(p => new string(p));
}
from e1 in set
from e2 in set
...
from eN in set
select new [] { e1, e2, .., eN }
public static IEnumerable<T[]> RepeatingPermutations<T>(this T[] set, int N)
{
    var result = new T[N];
    var indices = new int[N];
    for (int pos = 0, index = 0; ;)
    {
        for (; pos < N; pos++, index = 0)
        {
            indices[pos] = index;
            result[pos] = set[index];
        }
        yield return result;
        do
        {
            if (pos == 0) yield break;
            index = indices[--pos] + 1;
        }
        while (index >= set.Length);
    }
}
A : N=2 Count=         676 Time=00:00:00.0000467 Memory=     29K
B1: N=2 Count=         676 Time=00:00:00.0000263 Memory=     16K
B2: N=2 Count=         676 Time=00:00:00.0000189 Memory=      8K

A : N=3 Count=      17,576 Time=00:00:00.0010107 Memory=    657K
B1: N=3 Count=      17,576 Time=00:00:00.0003673 Memory=    344K
B2: N=3 Count=      17,576 Time=00:00:00.0001415 Memory=      8K

A : N=4 Count=     456,976 Time=00:00:00.0184445 Memory=  2,472K
B1: N=4 Count=     456,976 Time=00:00:00.0096189 Memory=  2,520K
B2: N=4 Count=     456,976 Time=00:00:00.0033624 Memory=      8K

A : N=5 Count=  11,881,376 Time=00:00:00.4281349 Memory=    397K
B1: N=5 Count=  11,881,376 Time=00:00:00.2482835 Memory=  4,042K
B2: N=5 Count=  11,881,376 Time=00:00:00.0887759 Memory=      8K

A : N=6 Count= 308,915,776 Time=00:00:11.2697326 Memory=  1,688K
B1: N=6 Count= 308,915,776 Time=00:00:06.5638404 Memory=  1,024K
B2: N=6 Count= 308,915,776 Time=00:00:02.2674431 Memory=      8K
var charSet = Enumerable.Range('A', 'Z' - 'A' + 1).Select(c => (char)c).ToArray();
var charPermutations = charSet.RepeatingPermutations(3);
var stringSet = new string(charset);
var stringPermutations = stringSet.RepeatingPermutations(3);
var charPermutationList = charSet.RepeatingPermutations(3)
    .Select(p => (char[])p.Clone()).ToList();
public static IEnumerable<T[]> Clone<T>(this IEnumerable<T[]> source)
{
    return source.Select(item => (T[])item.Clone());
}
var charPermutationList = charSet.RepeatingPermutations(3).Clone().ToList();