读取空间分隔整数

时间:2014-07-01 21:57:04

标签: c# performance input

我要从stdin读取一堆空格分隔的整数(35 33 2 3 251等)。输入可以是数百万英镑,所以我想确保尽可能快地读取。目前,我很确定情况并非如此:)

这就是我所拥有的:

string[] stringArr = Console.ReadLine().Split(' ');
var len = stringArr.Length;
int[] intArr = new int[len];
for (int i = 0; i < len; i++)
    intArr[i] = Convert.ToInt32(stringArr[i]);     

以上就是诀窍,但对我来说似乎很笨拙。我过去在C#中确实没有使用stdin,但我想有更快的方法可以做到这一点吗?

2 个答案:

答案 0 :(得分:5)

你可以通过逐字逐句地阅读来做到最好:

static void Main(string[] args)
{
    foreach (int i in Read(Console.In))
    {
        Console.WriteLine(i);
    }
}

static IEnumerable<int> Read(TextReader rdr)
{
    int ch;
    bool neg = false;
    int value = 0;
    int count = 0;

    while (-1 != (ch = rdr.Read()))
    {
        if (ch == 9 || ch == 10 || ch == 13 || ch == 32)
        {
            if (count > 0)
                yield return neg ? -value : value;  
            count = 0;
            value = 0;
            neg = false;
        }
        else if (count == 0 && ch == '-')
        {
            neg = true;
        }
        else if (ch >= '0' && ch <= '9')
        {
            count++;
            value = value*10 + (ch - '0');
        }
        else
            throw new InvalidDataException();
    }

    if (count > 0)
        yield return neg ? -value : value;  
}

答案 1 :(得分:2)

这不是最佳答案,但它正朝着正确的方向发展,因为它避免了昂贵的问题。 Split并解析:

var str = "10 20 13 45 78";

var ints = new List<int>(str.Length / 2); // Approximating the likely final size of the int array
int result = 0;
for(var i = 0; i < str.Length; i++)
{
    var c = str[i];

    if(c == ' ')
    {
        ints.Add(result);
        result = 0;
        continue;
    }

    result = 10 * result + (c - '0');
}

    // We didn't add the last char yet
var lastChar = str[str.Length - 1];

if(lastChar != ' ')
{
    ints.Add(result);
}

之后,您可以尝试循环展开,不安全的内存访问以及估计整数列表的最终大小的不同启发式方法(或者可能懒得用yield return生成它们而不是缓冲它们)。所有这些都取决于你的日期是什么样的以及它的大小。

请注意,这假设您的所有整数都是正数,但添加对负数的支持是微不足道的。