所以我想说我有一个字符串数组:
string[] values = new[] { "1", "2", "3", "1.5", "56.5", "8" };
让我们说我必须遍历这些值并执行以下操作:
将它舍入到最近的偶数(如果它只是一个双数)
舍入后删除数字的小数部分。
如果数字为负数,请删除标志。
string[] values = new[] { "1", "2", "3", "1.5", "56.5", "8" };
for (int i = 0; i < values.Length; i++)
{
file[i].Value = ((Int32)Math.Abs(Math.Round(Double.Parse(values[i]), MidpointRounding.ToEven))).ToString();
}
与执行此操作基本相同:
string[] values = new[] { "1", "2", "3", "1.5", "56.5", "8" };
for (int i = 0; i < values.Length; i++)
{
String strValue = values[j];
Double dblValue = Double.Parse(strValue);
Double dblRoundedValue = Double.Parse(dblValue);
Int32 intValue = (Int32)dblRoundedValue;
Int32 intAbsValue = Math.Abs(intValue);
String finalValue = intAbsValue.ToString();
file[i].Value = finalValue;
}
该阵列中可能有超过一百万个值,所以有没有办法让这个过程更有效?
答案 0 :(得分:5)
此操作本质上是可并行化的(如果这是一个单词)。 Parallel.ForEach
循环,并行Linq管道或类似的东西会缩短执行时间。
string[] values = new[] { "1", "2", "3", "1.5", "56.5", "8" };
var file = values.AsParallel()
.Select(s => Double.Parse(s))
.Select(d => (int)Math.Round(d))
.Select(i => Math.Abs(i).ToString())
.ToArray();
答案 1 :(得分:4)
嗯,我尝试了一些东西,并且在考虑是否有必要将其解析为Double之前,使用了超新星的建议来检查字符串中的小数点,以及Andrew Cooper的建议使用Parallel.For我得到
的结果Init...Done
Simple
20024
LookingAtString
8082
ParallelConvertLookingAtString
3559
Simple
19552
LookingAtString
7985
ParallelConvertLookingAtString
3595
使用以下代码...
using System;
using System.Diagnostics;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
const int nNumbers = 20000000;
static string[] values = new string[nNumbers];
static string[] file = new string[nNumbers];
static Random rand = new Random();
// Create some sample data.
static void Init()
{
string sgn = "";
for (int i = 0; i <= nNumbers - 1; i++)
{
sgn = rand.Next(51) == 1 ? "-" : "";
if (rand.Next(4) == 1)
{
values[i] = sgn + (rand.NextDouble() * 100).ToString();
}
else
{
values[i] = sgn + rand.Next(100);
}
}
}
static void ConvertSimple()
{
for (int i = 0; i <= nNumbers - 1; i++)
{
file[i] = Math.Abs(Math.Round(double.Parse(values[i]), MidpointRounding.ToEven)).ToString();
}
}
static void ConvertLookingAtString()
{
for (int i = 0; i <= nNumbers - 1; i++)
{
if (values[i].IndexOf('.') >= 0)
{
file[i] = Math.Abs(Math.Round(double.Parse(values[i]), MidpointRounding.ToEven)).ToString();
}
else
{
file[i] = values[i].TrimStart('-');
}
}
}
static void ParallelConvertLookingAtString()
{
Parallel.For(0, nNumbers, i =>
{
if (values[i].IndexOf('.') >= 0)
{
file[i] = Math.Abs(Math.Round(double.Parse(values[i]), MidpointRounding.ToEven)).ToString();
}
else
{
file[i] = values[i].TrimStart('-');
}
});
}
static void Main()
{
Console.Write("Init...");
Init();
Console.WriteLine("Done");
Stopwatch sw = new Stopwatch();
// run each test twice
for (int testNum = 0; testNum < 2; testNum++)
{
sw.Reset();
sw.Start();
ConvertSimple();
sw.Stop();
Console.WriteLine("Simple\n" + sw.ElapsedMilliseconds.ToString());
sw.Reset();
sw.Start();
ConvertLookingAtString();
sw.Stop();
Console.WriteLine("LookingAtString\n" + sw.ElapsedMilliseconds.ToString());
sw.Reset();
sw.Start();
ParallelConvertLookingAtString();
sw.Stop();
Console.WriteLine("ParallelConvertLookingAtString\n" + sw.ElapsedMilliseconds.ToString());
}
Console.ReadLine();
}
}
}
请注意,这是使用了两千万个样本,而不是你建议的一百万个样本,大约三分之一的值是分数,大约百分之二是负数。你没有给出那些预期的分数,所以我做了一些事情。
有些位可能是非最佳C#,因为我是从VB转换的。在具有6GB RAM的Intel Core i7 920上运行,编译为在x64上运行。
编辑:是的,所以我的回答是上面的ParallelConvertLookingAtString
方法。
答案 2 :(得分:1)
Double dblValue;
Double dblRoundedValue;
Int32 intValue;
Int32 intAbsValue;
String finalValue;
for (int i = 0; i < values.Length; i++)
{
strValue = values[j];
if (!Int32.TryParse(strValue, out intValue))
{
//dblValue = Double.Parse(strValue);
//dblRoundedValue = Double.Parse(dblValue);
//intValue = (Int32)dblRoundedValue;
intValue = (Int32)(Double.Parse(strValue));
}
//intValue = Math.Abs(intValue);
//finalValue = intValue .ToString();
file[i].Value = (Math.Abs(intValue)).ToString();
}
但我不明白两个Double.Parse 如果你需要,请把它们放回去 并将其转换为并行
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 16;
Parallel.For(0, values.Length, parallelOptions, i =>
{
strValue = values[j];
if (!Int32.TryParse(strValue, out intValue))
{
intValue = (Int32)(Double.Parse(strValue));
}
if (intValue < 0) intValue = -intValue;
file[i].Value = intValue.ToString();
});
我认为垃圾将是最快的
string[] values = new string[] { "1", "2", "3", "1.5", "56.5", "8" };
string[] files = new string[values.Length];
HashSet<char> lt5 = new HashSet<char> {'0','1','2','3','4'};
bool haveDecimal;
bool haveDecimalConfirmed;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < values.Length; i++)
{
sb.Clear();
haveDecimal = false;
haveDecimalConfirmed = false;
foreach(char c in values[i])
{
if (haveDecimal)
{
if (lt5.Contains(c))
{
files[i] = sb.ToString();
}
else
{
files[i] = (Int32.Parse(sb.ToString()) + 1).ToString();
}
haveDecimalConfirmed = true;
break;
}
else if (c == '.')
{
haveDecimal = true;
continue;
}
if (c == '-') continue;
sb.Append(c);
}
if (!haveDecimalConfirmed) files[i] = sb.ToString();
}
答案 3 :(得分:1)
一些想法:
我对此进行了测试,如果你说所有元素都相同,它会快得多。少数不同的元素可能会更快。但是如果元素都不同,它会占用大量内存,而且一旦Hash变得太大,你就会想要限制它。
字符串是一个字符数组。而不是转换为双倍,迭代字符直到你到达第一个&#34;。&#34;然后采取下一个数字。转换文本(忽略任何 - )之前。到整数。如果之后的值。是5,6,7,8,9然后将1加到该整数。
示例:
Input: "-1002.55"
Text between - and . is: "1002"
Converted to int this is: 1002
Character immediately after . is: "5"
Result: 1002 + 1 = 1003
那是圆到最近的。如果您需要舍入到最接近的偶数,请查看之前的数字。如果之后有一个,以及之前的数字。是1,3,5,7,9然后添加到最终的数字。
答案 4 :(得分:-3)
假设你是指&#34;偶数&#34;表示&#34;最接近的整数&#34;而不是&#34; 2&#34;的整数倍。 假设您的意思是从所有数字中删除负号,而不是仅使用舍入的数字。
您认为您的输入字符串始终有效Double格式,这是否合理?假设没有使用科学记数法格式化的数字,请检查每个输入字符串的小数点,它比解析更快,并测试小数部分。没有小数点,不需要舍入。