跟随字符数组获取下一个字符串

3

我有一个字符数组,完全是随机的,除了每个字符最多出现一次。

我还有一个字符串,其中只包含存在于该数组中的字符。我希望这个字符串能够像"111"变成"112"或者"aaa"变成"aab"那样"向上计数"。

假设字符数组包含1,2和3。上面的例子可以正常工作,但当字符串为"333"(应变成"1111")时,我的函数返回一个空或错误的字符串

如果我再次调用该函数并提供错误的字符串,几次后它就会返回正确的值("1111")。

为什么会发生这种情况?

这是我的函数:

Public Function getNextString(ByVal currentStr As String, ByVal pattern() As Char) As String 
    'currentStr is the string which I want to count upwards, pattern() is the array of chars

    Dim nextStr As String = ""

    Dim currentStrArray() As Char = currentStr.ToCharArray
    Dim currenStrPosition As Integer = currentStrArray.Length - 1

    Dim finished As Boolean = False
    Do Until finished = True
        Dim newPosition As Integer = getPositionInArray(currentStrArray(currentStrPosition)) 'this is a custom function, should be self-explaining
        If newPosition = Nothing Then Return Nothing
        newPosition += 1

        Try
            currentStrArray(currenStrPosition) = pattern(newPosition)
            finished = True
        Catch ex As IndexOutOfRangeException
            currentStrArray(currentStrPosition) = pattern(0)
            currentStrPosition -= 1
        End Try

        If currentStrPosition < 0 Then
            nextStr = pattern(0)
            finished = True
        End If
    Loop

    For i As Integer = 0 To currentStrArray.Length - 1
        nextStr = nextStr & currentStrArray(i)
    Next

    Return nextStr
End Function

有什么想法吗?

编辑:

举个例子,我有数组{"1","2","3"}。我的string首先是"111"。我想测试这些strings的哈希值。在测试完这个字符串后,我需要下一个string"112"。然后是"113""121""122"等等。当字符串到达"333"并且字符串不是我要找的那一个时,很明显它不是只有3个字符的字符串(使用该数组可能的所有3个字符组合已经尝试过)。所以我需要从4个字符开始重新开始。这就是为什么"333"被认为应该变成"1111"的原因。 希望这可以帮助。

第二次编辑:

我发现错误了。我重新定义了我的数组,因此最后一个索引为空。这使得我的strings看起来很奇怪。谢谢你们提供的有效解决方案,祝你们度过愉快的一天!


2
为什么333应该变成1111? - Tim Schmelter
1
我认为这基本上是用随机字符替换数字,所以如果数组是{"a", "b", "c"},你应该将"a"视为0,"b"视为1,"c"视为3,并在三进制中计数。 - Zohar Peled
@Zohar Peled 这些字符可以是任何Ascii字符,数组大小可以从1个字符到256个字符不等... 我该怎么做? - Bumblebee
@Ian 我还不明白为什么这个要求那么有趣... 对我来说它似乎很合理!不过我喜欢你的回答,如果我有足够的声望,我会点赞的。 - Bumblebee
@TimSchmelter-我认为你的观点是正确的,即"333" + 1 <> "1111"。请看我的回答-我已经证明了"333" + 1 = "2111" - Enigmativity
显示剩余4条评论
3个回答

0

如果我理解正确,您想要在特定基数(您数组的长度)中递增。您需要的是一个映射函数,将您的数组字符映射到它们各自的数字,然后从您的基数转换为十进制,递增,再转换回来并重新映射。

您能否检查一下这个链接是否有帮助?在.NET中将十进制数快速转换为任何基数的最快方法?

我刚刚用c#编写了以下代码,它似乎可以工作。

    static void Main(string[] args)
    {
        char[] definition = new char[] { 'a', 'b', 'c', 'd', '9', 'x', 'y', 'z', '1', '2', '3'};
        string helperstring = new String(definition);
        int basenumber = definition.Length;
        string mynumberasstring = "333";
        Console.WriteLine(mynumberasstring);
        int correspondingdecimal = 0;
        for (int i = 0; i < mynumberasstring.Length; i++)
        {
            char x = mynumberasstring[mynumberasstring.Length - i - 1];
            int index = helperstring.IndexOf(x);
            int magnitude = 1;
            for (int j = 0; j < i; j++)
                magnitude *= basenumber;
            Console.WriteLine(x + " -> " + index);
            correspondingdecimal += magnitude * index;
        }
        Console.WriteLine(correspondingdecimal + " -> " + ++correspondingdecimal);

        List<int> indicesofnewnumber = new List<int>();

        int newmagnitude = basenumber;
        while(correspondingdecimal > 0)
        {
            int div = correspondingdecimal / basenumber;
            int remainder = correspondingdecimal % basenumber;

            Console.WriteLine("{0} -> {1} ; {2}", correspondingdecimal, div, remainder);

            indicesofnewnumber.Add(remainder);
            correspondingdecimal = div;
        }
        string newnumberasstring = "";
        for (int i = 0; i < indicesofnewnumber.Count; i++)
            newnumberasstring += definition[indicesofnewnumber[indicesofnewnumber.Count - 1 - i]];

        Console.WriteLine(newnumberasstring);
        Console.ReadLine();
    }

使用我的函数,它会使用数组的索引递增计数(这个术语是否正确?)。例如,在{"a","b"}中,"a"是索引0;我将其替换为索引1。也许我误解了你的意思……不确定。 - Bumblebee
我会将a映射为0,b映射为1。因此,“ba”将变为“10”,可以转换为2;增加3变为“11”,映射为“bb”。 - Geoffrey

0
这是我能想到的最简短的代码,用于将数字转换为任意基数和任意数字:
Dim convert As Func(Of Integer, Char(), String) = Nothing
convert = Function (n, cs) _
    If(n \ cs.Length = 0, "", convert(n \ cs.Length, cs)) + cs(n Mod cs.Length)

所以,要将4转换为二进制,我可以使用convert(4, { "0"c, "1"c }),然后我会得到100

作为一种合理性检查,如果我使用String.Join(", ", Enumerable.Range(0, 32).Select(Function (n) convert(n, { "0"c, "1"c })))来查看从零开始的前32个二进制数,那么我会得到以下结果:

0, 1, 10, 11, 100, 101, 110, 111, 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111, 10000, 10001, 10010, 10011, 10100, 10101, 10110, 10111, 11000, 11001, 11010, 11011, 11100, 11101, 11110, 11111

或者,如果我使用String.Join(", ", Enumerable.Range(0, 102).Select(Function (n) convert(n, "0123456789".ToCharArray())))来查看从零开始的前102个十进制数,那么我会得到以下结果:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101

现在我可以使用相同的代码从数字 { "1"c, "2"c, "3"c } 中获取前50个数字,使用 String.Join(", ", Enumerable.Range(0, 50).Select(Function (n) convert(n, "123".ToCharArray()))),结果如下:

1, 2, 3, 21, 22, 23, 31, 32, 33, 211, 212, 213, 221, 222, 223, 231, 232, 233, 311, 312, 313, 321, 322, 323, 331, 332, 333, 2111, 2112, 2113, 2121, 2122, 2123, 2131, 2132, 2133, 2211, 2212, 2213, 2221, 2222, 2223, 2231, 2232, 2233, 2311, 2312, 2313, 2321, 2322

这是使用数字{"1"c, "2"c, "3"c}进行正确的“计数”。因此,在这个编号系统中,"333" + 1 = "2111"是正确的。这与在我们的十进制系统中说999 + 1 = 1000是相同的-显然不会从999 + 1 = 0000,这意味着"333" + 1 = "1111"在这个“123”系统中的含义。严格来说,我应该写"333" + "2" = "2111"(因为"2"代表1)。
如果您想要所有组合,则需要在左侧用“零”字符填充字符串-在这种情况下,是1。然后,这段代码:
String.Join(", ", _
    Enumerable _
        .Range(0, 500) _
        .Select(Function (n) convert(n, "123".ToCharArray()).PadLeft(4, "1"c)) _
        .Where(Function (x) x.Length = 4))

...给出以下81个数字:

1111、1112、1113、1121、1122、1123、1131、1132、1133、1211、1212、1213、1221、1222、1223、1231、1232、1233、1311、1312、1313、1321、1322、1323、1331、1332、1333、2111、2112、2113、2121、2122、2123、2131、2132、2133、2211、2212、2213、2221、2222、2223、2231、2232、2233、2311、2312、2313、2321、2322、2323、2331、2332、2333、3111、3112、3113、3121、3122、3123、3131、3132、3133、3211、3212、3213、3221、3222、3223、3231、3232、3233、3311、3312、3313、3321、3322、3323、3331、3332、3333。

...而81是组合的总数,如3 x 3 x 3 x 3 = 81


以下是一对函数,可进行双向转换:

Function Convert(number As Integer, digits As Char()) As String
    Dim r = digits(number Mod digits.Length).ToString()
    If number \ digits.Length <> 0 Then
        r = Convert(number \ digits.Length, digits) + r
    End If
    Return r
End Function

Function Convert(number As String, digits As Char()) As Integer
    Dim r = Array.IndexOf(digits, number(0))
    If number.Substring(1).Length > 0 Then
        r = r * digits.Length + Convert(number.Substring(1), digits)
    End If
    Return r
End Function

0

我会先将其转换为数字,加1,然后再转换回字符串。

将字符串转换为数字:

Function ConvertStringToNumber(input As String, pattern As Char()) As Integer
    Dim number As Integer = 0
    Dim charDigits = pattern.ToList()
    Dim numberBase = charDigits.Count
    For i As var = 0 To input.Length - 1
        Dim digit = charDigits.IndexOf(input(input.Length - 1 - i))
        If digit <> -1 Then
            number += digit * CInt(Math.Pow(numberBase, i))
        End If
    Next
    Return number
End Function

将数字转换回字符串:

Function convertNumberToString(number As Integer, pattern As Char()) As String
    Dim charDigits = pattern.ToList()
    Dim numberBase = charDigits.Count
    Dim buffer = New Stack(Of Char)()
    'var j = buffer.Length;
    While number > 0
        buffer.Push(charDigits(number Mod numberBase))
        number = number / numberBase
    End While
    Dim sb = New StringBuilder()
    While buffer.Count > 0
        sb.Append(buffer.Pop())
    End While

    Return sb.ToString()
End Function

现在你有了转换函数,你只需要像这样做:

Function getNextString(ByVal currentStr As String, ByVal pattern() As Char) As String
    Dim number = ConvertStringToNumber(currentStr, pattern)
    number += 1
    Return convertNumberToString(number, pattern)
End Function

我用C#编写了我的答案,并使用在线工具将其转换为VB.NET。我怀疑转换并不完美,因为C#版本按照我的意图正常工作。 - Zohar Peled
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Bumblebee
@Enigmativity 嗯,我已经很久没有写vb.net了。几年前转到了c#,并且一直没有回头看,所以如果我的回答中有些错误,希望StackOverflow社区能够原谅我。 - Zohar Peled
@ZoharPeled - 哈哈,希望你没有生气!你只需要将 number = number / numberBase 更改为 number = number \ numberBase 就可以避免从 Double 转换为 Integer 时出现无效转换。 - Enigmativity
@Enigmativity 没关系 :-) - Zohar Peled
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接