C# 如何比较排列

C# 如何比较排列,c#,permutation,string-comparison,C#,Permutation,String Comparison,上下文 我正在构建一个基于Enigma的有趣的加密应用程序 我在codegolf.stackexchange.com上提出了这个问题,但他们说这是离题的,建议在这里提出 该设计的核心是虚拟转子,它是Enigma中使用的物理转子的数字等价物,简单地说,就是一个可见字母映射到一个秘密字母 例如,如果给定转子上的可见字母是a-Z,那么我们可以这样描述秘密映射: ABCDEFGHIJKLMNOPQRSTUVWXYZ - A-Z EKMFLGDQVZNTOWYHXUSPAIBRCJ - Rotor I A

上下文

我正在构建一个基于Enigma的有趣的加密应用程序

我在codegolf.stackexchange.com上提出了这个问题,但他们说这是离题的,建议在这里提出

该设计的核心是虚拟转子,它是Enigma中使用的物理转子的数字等价物,简单地说,就是一个可见字母映射到一个秘密字母

例如,如果给定转子上的可见字母是a-Z,那么我们可以这样描述秘密映射:

ABCDEFGHIJKLMNOPQRSTUVWXYZ - A-Z
EKMFLGDQVZNTOWYHXUSPAIBRCJ - Rotor I
AJDKSIRUXBLHWTMCQGZNPYFVOE - Rotor II
BDFHJLCPRTXVZNYEIWGAKMUSQO - Rotor III
问题

我在生成新的随机映射方面没有问题,但是我怎样才能比较它们的相似性呢

我想做的是生成一组潜在的新转子映射,并以某种方式评估它们的相似性,例如:

BDFHJLCPRTXVZNYEIWGAKMUSQO - Rotor III
ZGFHJLCPRXTVDNYEIWBAMUKOQS - Random Rotor A
VZBRGITYUPSDNHLXAWMJQOFECK - Random Rotor B
NYEIWGAKMUSQOBDFHJLCPRTXVZ - Random Rotor C
与转子III相比,随机转子A不同,但B的变化更明显。转子C看起来和转子III有很大的不同,但事实并非如此,它只是将转子III切成两半,第二部分放在第一部分前面

如何比较这种性质的字符串或字符数组

仅供参考,我会使用C来构建这个,但是我很乐意接受我可以实现的任何合理的逻辑

更新


比较不必非常精确。字符串的长度将超过26-将在100+左右变化,尽管所有字符串的长度相同。排列的数量也会有所不同,但可能是100+。

我建议您使用Levenshtein距离。我认为你错了,转子C和转子B一样不同,这是基于使用它来映射可见字母的结果。相似性/差异中重要的是对最终输出的影响


一种选择是简单地编写自己的方法来确定两个字符串之间的相似性

这里有两种方法可以考虑相似性,因为字符串总是相同的长度,并且包含相同的字符。一个是相同位置的字符百分比,另一个是第二个字符串中所有字符与其在第一个字符串中的位置之间的总距离百分比

第一个很直截了当:

private static int GetSimilarity1(string first, string second)
{
    if (first == null) return second == null ? 100 : 0;

    // Set similarity to the percentage of characters in the same position
    var matches = first.Count(chr => first.IndexOf(chr) == second.IndexOf(chr));
    return (int)(matches / (decimal)first.Length * 100);
}
第二个是第二个字符串中的每个字符与第一个字符串中的索引之间的距离,然后除以最坏情况下它与索引之间的最大距离。这将导致精确匹配的低值0,或距离越远,值越高。然后,将该数字转换为一个百分比,将其从一个数字中减去,将精确匹配的坏百分比0转换为精确匹配的好百分比1,然后乘以100。然后将该数字添加到运行总数中

最后,将总数除以字符数,得到最终的相似性百分比

为了计算一个值与实际位置之间的最大距离,我将它在第一个数组中的索引值与length-index-1的值进行比较,以较大者为准,这是字符可能达到的最远索引:

private static int GetSimilarity2(string first, string second)
{
    if (first == null) return second == null ? 100 : 0;

    int distance = 0;

    for(int i = 0; i < first.Length; i++)
    {
        var thisDist = Math.Abs(second.IndexOf(first[i]) - i);
        var worstDist = Math.Max(first.Length - i - 1, i);
        distance += (int)((1 - thisDist / (decimal) worstDist) * 100);
    }

    return distance / first.Length;
}
输出


您是否关心顺序或字符匹配的数量?取决于您所指的不同和/或相似。看起来您想知道两个字符串中都包含多少特定长度的子字符串。这只是一系列匹配子字符串的循环。您检查的循环数和长度决定了字符串的不同或相似程度。@maccettura-每个映射都是相同字符的排列,唯一的区别是它们的排列方式。顺序即顺序是相关的,因为相同的顺序使它们太相似了-参见随机转子C示例,与转子III相比。您可以尝试将字符串中字符索引的差异相加,即转子III[B]=0-转子C[B]=13=-13,转子III[Q]=24-转子C[Q]=11=13,-13+13=0,其他24个字母也是如此。大多数情况下,似乎总和离0越远,字符就越混乱。当然,它可以通过其他方式计算为0…感谢您在回答@Rufus L时付出了如此多的努力。让我试一下可能需要几天时间。当然,这是一个有趣的问题。不过,它们都没有你想要的模式匹配。希望你能找到适合你的东西。
private static void Main()
{
    var rotorIII = "BDFHJLCPRTXVZNYEIWGAKMUSQO";
    var randRotorA = "ZGFHJLCPRXTVDNYEIWBAMUKOQS";
    var randRotorB = "VZBRGITYUPSDNHLXAWMJQOFECK";
    var randRotorC = "NYEIWGAKMUSQOBDFHJLCPRTXVZ";

    Console.WriteLine("Method 1: Rotor III -> Random Rotor A: {0}", 
        GetSimilarity1(rotorIII, randRotorA));
    Console.WriteLine("Method 1: Rotor III -> Random Rotor B: {0}", 
        GetSimilarity1(rotorIII, randRotorB));
    Console.WriteLine("Method 1: Rotor III -> Random Rotor C: {0}", 
        GetSimilarity1(rotorIII, randRotorC));

    Console.WriteLine("-----------------------------------------");

    Console.WriteLine("Method 2: Rotor III -> Random Rotor A: {0}", 
        GetSimilarity2(rotorIII, randRotorA));
    Console.WriteLine("Method 2: Rotor III -> Random Rotor B: {0}", 
        GetSimilarity2(rotorIII, randRotorB));
    Console.WriteLine("Method 2: Rotor III -> Random Rotor C: {0}", 
        GetSimilarity2(rotorIII, randRotorC));

    // Wait for input before closing
    Console.WriteLine("\nDone!\nPress any key to exit...");
    Console.ReadKey();
}