簡體   English   中英

將雙精度列表轉換為分組字符串

[英]Convert a double list to a grouped string

該程序的輸入為雙精度列表,輸出為包含按值分組的列表值的字符串。 如果列表值相等,則將它們分組。 像這樣的東西:輸入9,77,5,5,31 =>輸出9 77 2 * 5 31

為此,我在C#中創建了一個算法(在Java中,我認為幾乎是相同的),但是我不確定在速度或代碼質量方面是否可以改進它,或者是否存在一些我看不到的錯誤。 下面還有另外一些輸入,輸出示例的算法。

          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);

如果您發現一些錯誤或看到可以完成的改進,請告訴我。

另外,如果您知道此要求的另一種實現,請添加它,以便可以對算法之間的結果,速度,代碼質量進行比較...並找到處理此問題的最佳方法。

由於要求僅對連續的相等值進行分組,因此另一個答案中提到的Dictionary和LINQ GroupBy方法不適用,因為它們會對諸如1,2,1類的輸入序列產生不正確的結果。 同樣,也沒有標准的LINQ方法來進行這種分組(最終的Aggregate方法除外,但for / foreach循環等效項而言,效率不高)。

不久,您的算法最適合此類任務。 但是執行不是。

主要的瓶頸是Peroxy提到的字符串連接,該字符串連接(在其他答案中也提到了)可以通過使用StringBuilder類輕松修復。 一旦執行此操作,性能將很好。

另一個問題我在執行看到的是特殊值(使用double.MinValue ),重復的極端情況的檢查,遞減for身體等內部循環變量所以,雖然它可能工作,我不直接看到一個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();
}

IMO比較容易理解。 請注意,沒有重復的代碼,沒有特殊的值,並且循環變量i只能在外部循環體內的一個位置進行。 同樣,這與性能無關(這由StringBuilder用法提供),而僅僅是可讀性,冗余消除和較少的錯誤傾向。

就個人而言,我在這里發現使用Dictionary潛力很大,這是我使用字典實現的一個快速解決方案:

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);

如果您想要一種效率不高的LINQ單襯板解決方案:

string result = string.Join(" ", input.GroupBy(i => i)
                                       .Select(x => 
                                       x.Count() > 1 ? 
                                       $"{x.Count()}*{x.Key} " : 
                                       $"{x.Key} "));

但是,我相信您的方法寫得很好,雖然比字典的可讀性差,但是解決方案的主要缺點是,在構建最終字符串時您使用的是字符串,您肯定應該使用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.Append(currentElem + " ")代替listAsString += currentElem + " "

如果僅對n < 1000集合進行操作,則可以使用GroupBy如果您希望在速度上提高可讀性,請使用Dictionary解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM