0

我必须编写一个使用哈希表的程序,并且键/值由用户输入。在程序中,我必须输出所有的键,但是如果任何键以小“a”开头,我必须让它以大“A”开头。我在最后一步有问题。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Hashtable hashtable = new Hashtable();
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("Vnesete kluc");
                string kluc = Console.ReadLine();
                Console.WriteLine("Vnesete podatok");
                string podatok = Console.ReadLine();
                hashtable.Add(kluc, podatok);
            }

            foreach (string klucevi in hashtable.Keys)
            {
                if (klucevi[0] == 'a')
                {
                    klucevi[0] = 'A';
                }
                Console.WriteLine(klucevi);
            }

        }
    }
}

我在将字符串的第一个元素从“a”转换为“A”的行中遇到错误。

4

2 回答 2

3

您不能动态更改键。最简单的方法是在添加到集合之前检查密钥:

for (int i = 0; i < 10; i++)
{
    Console.WriteLine("Vnesete kluc");
    string kluc = Console.ReadLine();
    if (kluc.StartsWith("a"))
        kluc = "A" + kluc.Substring(1);
    Console.WriteLine("Vnesete podatok");
    string podatok = Console.ReadLine();
    hashtable.Add(kluc, podatok);
}
于 2013-10-29T14:13:12.330 回答
1

您的问题与哈希表无关。您有一个编译错误,因为在 .NET 中字符串是不可变的。

其次,这是不相关的,不能分配 foreach 循环变量。

所以,而不是

foreach (string klucevi in *whatever*)
{
    if (klucevi[0] == 'a')
    {
        klucevi[0] = 'A';
    }
    Console.WriteLine(klucevi);
}

采用

foreach (string klucevi in *whatever*)
{
    var temp = klucevi;

    if (temp[0] == 'a')
    {
        StringBuilder sb = new StringBuilder(temp);

        sb[0] = 'A';

        temp = sb.ToString();
    }
    Console.WriteLine(temp);
}

不要忘记包含using System.Text;声明。

更新:上面的 aswer 向您展示了一种在 .NET 中修改字符串的通用方法,而不仅仅是替换一个字符。

此外,一些人对这种方法的效率提出了担忧。他们错了。这篇关于Strings Undocumented的优秀文章中的更多信息。

更新2:我喜欢被挑战。虽然它与手头的问题完全无关,但与使用 StringBuilder 相比,使用"A" + temp.Substring(1). 因为我喜欢事实,并且我认为一些读者会同意,所以我运行了一个小基准。

我在使用 .NET 4.5 作为 32 位和 64 位进程的 64 位 Windows 7 机器上运行测试。事实证明,StringBuilder 方法总是比替代方法快 20% 左右。内存使用情况大致相同。YMMV。

对于那些想重复测试的人,这里是源代码:

using System;
using System.Diagnostics;
using System.Text;

static class Program
{
    static void Main(string[] args)
    {
        for (int length = 50; length <= 51200; length = length * 2)
        {
            string input = new string(' ', length);

            // warm up
            PerformTest(input, 1);

            // actual test
            PerformTest(input, 100000);
        }
    }

    static void PerformTest(string input, int iterations)
    {
        GC.Collect();
        GC.WaitForFullGCComplete();

        int gcRuns = GC.CollectionCount(0);

        Stopwatch sw = Stopwatch.StartNew();

        for (int i = iterations; i > 0; i--)
        {
            StringBuilder sb = new StringBuilder(input);

            sb[0] = 'A';

            input = sb.ToString();
        }

        long ticksWithStringBuilder = sw.ElapsedTicks;
        int gcRunsWithStringBuilder = GC.CollectionCount(0) - gcRuns;

        GC.Collect();
        GC.WaitForFullGCComplete();

        gcRuns = GC.CollectionCount(0);

        sw = Stopwatch.StartNew();

        for (int i = iterations; i > 0; i--)
        {
            input = "A" + input.Substring(1);
        }

        long ticksWithConcatSubstring = sw.ElapsedTicks;
        int gcRunsWithConcatSubstring = GC.CollectionCount(0) - gcRuns;

        if (iterations > 1)
        {
            Console.WriteLine(
                "String length: {0, 5} With StringBuilder {1, 9} ticks {2, 5} GC runs, alternative {3, 9} ticks {4, 5} GC Runs, speed ratio {5:0.00}", 
                input.Length, 
                ticksWithStringBuilder, gcRunsWithStringBuilder, 
                ticksWithConcatSubstring, gcRunsWithConcatSubstring, 
                ((double)ticksWithStringBuilder) / ((double)ticksWithConcatSubstring));
        }
    }
}
于 2013-10-29T14:08:13.103 回答