Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将双精度列表转换为分组字符串_Java_C#_Algorithm_Performance_Testing - Fatal编程技术网

Java 将双精度列表转换为分组字符串

Java 将双精度列表转换为分组字符串,java,c#,algorithm,performance,testing,Java,C#,Algorithm,Performance,Testing,程序有一个输入和一个双精度列表,输出需要是一个字符串,包含按其值分组的列表值。如果列表值相等,则将对它们进行分组。 比如: 输入9,77,5,5,31=>输出9,77 2*5 31 我在Java中用C创建了一个算法,我认为这几乎与此相同,但我不确定它的速度或代码质量是否可以改进,或者它是否有一些我看不到的错误。下面是具有更多输入、输出示例的算法 List<double> input = new List<double> { 11, 32, 32, 43

程序有一个输入和一个双精度列表,输出需要是一个字符串,包含按其值分组的列表值。如果列表值相等,则将对它们进行分组。 比如: 输入9,77,5,5,31=>输出9,77 2*5 31

我在Java中用C创建了一个算法,我认为这几乎与此相同,但我不确定它的速度或代码质量是否可以改进,或者它是否有一些我看不到的错误。下面是具有更多输入、输出示例的算法

          List<double> input = new List<double> { 11, 32, 32, 43}; // output 11 2*32 43
        //List<double> input = new List<double> { 11, 11, 43, 43 }; // output 2*11 2*43
        //List<double> input = new List<double> { 10, 11, 12, 13, 14, 15, 16 }; // output 10 11 12 13 14 15 16
        //List<double> input = new List<double> { 11, 11, 11, 11, 11 }; // output 5 * 11
        //List<double> input = new List<double> { 11, 11, 32, 22, 22, 22, 4, 10, 10 }; // output 2*11 32 3*22 4 2*10

        string listAsString = string.Empty;
        double nextElem = double.MinValue;
        for (int i = 0; i < input.Count; i++)
        {
            double currentElem = input[i];

            if (i + 1 < input.Count)
            {
                nextElem = input[i + 1];
            }

            int equalCount = 0;
            while (currentElem.Equals(nextElem) && i < input.Count)
            {
                equalCount++;
                i++;
                currentElem = nextElem;

                if (i < input.Count)
                {
                    nextElem = input[i];
                }
            }

            if (equalCount < 2)
            {
                listAsString += currentElem + " ";
            }
            else
            {
                listAsString += equalCount + "*" + currentElem + " ";
                i--;
            }
        }

        Console.WriteLine(listAsString);
请让我知道,如果你注意到一些错误或看到一些可以做的改进


此外,如果您知道此要求的另一个实现,请添加它,以便可以对算法之间的结果、速度和代码质量进行比较。。。并找到处理此问题的最佳方法。

就我个人而言,我在这里看到了字典使用的巨大潜力,下面是我使用字典实现的一个快速解决方案:

var input = new List<double> { 9, 77, 5, 5, 31 };
var dict = new Dictionary<double, int>();
var listAsString = new StringBuilder();

foreach (var item in input)
{
    if (dict.ContainsKey(item))
        dict[item]++;
    else
        dict[item] = 1;
}

foreach (var item in dict)
{
    listAsString.Append(item.Value > 1 ? $"{item.Value}*{item.Key} " : $"{item.Key} ");
}

Console.WriteLine(listAsString);
但是,我相信你的方法写得很好,虽然可读性比字典的要差一点,但是你的解决方案的主要缺陷是,你在构建最终字符串时使用了字符串,你肯定应该使用StringBuilder,我在您的方法中介绍了StringBuilder,并对这三种方法进行了比较:

Dictionary    | Your method | GroupBy method
------------------------------------------------
 2 ms         |    0 ms     |    5 ms           n=3
 0 ms         |    0 ms     |    0 ms           n=6
 0 ms         |    0 ms     |    0 ms           n=12
 0 ms         |    0 ms     |    0 ms           n=24
 0 ms         |    0 ms     |    0 ms           n=48
 0 ms         |    0 ms     |    0 ms           n=96
 0 ms         |    0 ms     |    0 ms           n=192
 0 ms         |    0 ms     |    0 ms           n=384
 0 ms         |    0 ms     |    0 ms           n=768
 0 ms         |    0 ms     |    0 ms           n=1536
 1 ms         |    0 ms     |    1 ms           n=3072
 3 ms         |    2 ms     |    3 ms           n=6144
 5 ms         |    4 ms     |    6 ms           n=12288
 8 ms         |    7 ms     |    14 ms          n=24576
 14 ms        |    13 ms    |    25 ms          n=49152
 31 ms        |    32 ms    |    66 ms          n=98304
 80 ms        |    59 ms    |    146 ms         n=196608
 149 ms       |    123 ms   |    294 ms         n=393216
 246 ms       |    218 ms   |    504 ms         n=786432
 483 ms       |    428 ms   |    1040 ms        n=1572864
 999 ms       |    873 ms   |    2070 ms        n=3145728
 1995 ms      |    1784 ms  |    3950 ms        n=6291456
您的解决方案总是最快的,如果您想加快速度,请保留您的解决方案,但将其更改为使用StringBuilder,使用listAsString.AppendcurrentElem+而不是listAsString+=currentElem+


如果您只处理n<1000的集合,则可以使用GroupBy。如果您希望解决可读性问题而不是速度问题,则可以使用字典解决方案。

就个人而言,我在这里看到字典使用的巨大潜力,下面是我用字典实现的一个快速解决方案:

var input = new List<double> { 9, 77, 5, 5, 31 };
var dict = new Dictionary<double, int>();
var listAsString = new StringBuilder();

foreach (var item in input)
{
    if (dict.ContainsKey(item))
        dict[item]++;
    else
        dict[item] = 1;
}

foreach (var item in dict)
{
    listAsString.Append(item.Value > 1 ? $"{item.Value}*{item.Key} " : $"{item.Key} ");
}

Console.WriteLine(listAsString);
但是,我相信你的方法写得很好,虽然可读性比字典的要差一点,但是你的解决方案的主要缺陷是,你在构建最终字符串时使用了字符串,你肯定应该使用StringBuilder,我在您的方法中介绍了StringBuilder,并对这三种方法进行了比较:

Dictionary    | Your method | GroupBy method
------------------------------------------------
 2 ms         |    0 ms     |    5 ms           n=3
 0 ms         |    0 ms     |    0 ms           n=6
 0 ms         |    0 ms     |    0 ms           n=12
 0 ms         |    0 ms     |    0 ms           n=24
 0 ms         |    0 ms     |    0 ms           n=48
 0 ms         |    0 ms     |    0 ms           n=96
 0 ms         |    0 ms     |    0 ms           n=192
 0 ms         |    0 ms     |    0 ms           n=384
 0 ms         |    0 ms     |    0 ms           n=768
 0 ms         |    0 ms     |    0 ms           n=1536
 1 ms         |    0 ms     |    1 ms           n=3072
 3 ms         |    2 ms     |    3 ms           n=6144
 5 ms         |    4 ms     |    6 ms           n=12288
 8 ms         |    7 ms     |    14 ms          n=24576
 14 ms        |    13 ms    |    25 ms          n=49152
 31 ms        |    32 ms    |    66 ms          n=98304
 80 ms        |    59 ms    |    146 ms         n=196608
 149 ms       |    123 ms   |    294 ms         n=393216
 246 ms       |    218 ms   |    504 ms         n=786432
 483 ms       |    428 ms   |    1040 ms        n=1572864
 999 ms       |    873 ms   |    2070 ms        n=3145728
 1995 ms      |    1784 ms  |    3950 ms        n=6291456
您的解决方案总是最快的,如果您想加快速度,请保留您的解决方案,但将其更改为使用StringBuilder,使用listAsString.AppendcurrentElem+而不是listAsString+=currentElem+


如果您只对n<1000的集合进行操作,则可以使用GroupBy。如果您希望解决可读性问题而不是速度问题,请使用字典解决方案。

因为要求仅对连续的相等值进行分组,另一个答案中提到的Dictionary和LINQ GroupBy方法不适用,因为它们将为输入序列(如1,2,1)生成不正确的结果。此外,除了最终聚合方法外,并没有标准的LINQ方法来进行这种分组,但它只不过是for/foreach循环等效的低效方法

简而言之,您的算法是此类任务的最佳算法。但实施并非如此

主要的瓶颈是所提到的字符串连接,在另一个答案中也提到了这一点,通过使用StringBuilder类可以很容易地解决。一旦你这样做了,性能就会很好

我在实现中看到的另一个问题是使用特殊值double.MinValue、重复的角点大小写检查、在主体内部递减for循环变量等。因此,尽管它可能有效,而且我没有直接看到错误,但仅仅读取实现就很难遵循算法逻辑并发现潜在的错误。算法本身非常简单,我会这样实现:

static string ListAsString(List<double> input)
{
    var sb = new StringBuilder();
    for (int i = 0; i < input.Count; )
    {
        var value = input[i];
        int count = 1;
        while (++i < input.Count && input[i] == value)
            count++;
        if (sb.Length > 0) sb.Append(' ');
        if (count > 1) sb.Append(count).Append('*');
        sb.Append(value);
    }
    return sb.ToString();
}

这是国际海事组织比较容易遵循的。请注意,没有重复代码,没有特殊值,循环变量i仅在外部循环体中的一个位置执行。同样,这与StringBuilder的使用所提供的性能无关,只不过是可读性、冗余消除和不易出错。

因为要求只对连续的相等值进行分组,另一个答案中提到的Dictionary和LINQ GroupBy方法不适用,因为它们将为输入序列(如1,2,1)生成不正确的结果。此外,除了最终聚合方法外,并没有标准的LINQ方法来进行这种分组,但它只不过是for/foreach循环等效的低效方法

简而言之,您的算法是此类任务的最佳算法。但实施并非如此

主要的瓶颈是所提到的字符串连接,在另一个答案中也提到了这一点,通过使用StringBuilder类可以很容易地解决。一旦你这样做了,性能就会很好

我在实现中看到的另一个问题是使用特殊值double.MinValue、重复的角大小写检查、在主体内部递减for循环变量等 bably可以工作,我没有直接看到一个bug,仅仅阅读实现就很难遵循算法逻辑并发现潜在的bug。算法本身非常简单,我会这样实现:

static string ListAsString(List<double> input)
{
    var sb = new StringBuilder();
    for (int i = 0; i < input.Count; )
    {
        var value = input[i];
        int count = 1;
        while (++i < input.Count && input[i] == value)
            count++;
        if (sb.Length > 0) sb.Append(' ');
        if (count > 1) sb.Append(count).Append('*');
        sb.Append(value);
    }
    return sb.ToString();
}


这是国际海事组织比较容易遵循的。请注意,没有重复代码,没有特殊值,循环变量i仅在外部循环体中的一个位置执行。同样,这与StringBuilder使用所提供的性能无关,只是可读性、冗余消除和不易出错。

对于1,3,1,输出是1 3 1或2*1 3?这更像是代码评审的问题。嗨,安东宁,对于输入1 3 1,输出将是1 3 1。只有连续相等的数字将被分组。嗨,大卫,谢谢你的建议,我也将在那里发布!对于1,3,1,输出是1 3 1或2*1 3?这似乎更像是codereview的问题。se?Hi Antonín,对于输入1 3 1,输出将是1 3 1。只有连续相等的数字将被分组。嗨,大卫,谢谢你的建议,我也将在那里发布!你的努力肯定对我有用。在你最终将linq添加到你的答案之前,他一直在玩弄linq。NetFiddle运行了超过1mil的内存。当我接近1600万个元素时,我用字典方法遇到了内存问题。。很高兴它是有用的:-嗨Peroxy,谢谢你的详细解释!你的答案似乎涵盖了所有可能的nice实现。这很好,但OP指出只有连续的相等数字才会被分组。你的两个解给出了不同的结果。@AntonínLejsek是对的,我的解是不正确的,如果连续相等的数字只应该分组,我一开始没有看到这一点。。你应该参考伊万·斯托夫的答案。你的努力肯定对我有用。在你最终将linq添加到你的答案之前,他一直在玩弄linq。NetFiddle运行了超过1mil的内存。当我接近1600万个元素时,我用字典方法遇到了内存问题。。很高兴它是有用的:-嗨Peroxy,谢谢你的详细解释!你的答案似乎涵盖了所有可能的nice实现。这很好,但OP指出只有连续的相等数字才会被分组。你的两个解给出了不同的结果。@AntonínLejsek是对的,我的解是不正确的,如果连续相等的数字只应该分组,我一开始没有看到这一点。。你应该参考伊万·斯托夫的答案。