I have to format a collection of doubles to 2 decimal places and display it in a console app by seperating it with a comma (,).
I have used the following:
var result = GetResults() //returns 1.234125, 3.56345, 6.43254
Console.WriteLine(string.Join(",",result)
However this does not format the values to 2 decimal places. I'm looking to display 1.23,3.56,6.43 to the console. Also the elements in "result" collection could range for a few 1000 doubles.So I'm looking for an optimized piece of code which will not involve any boxing and will take the least time to display itself to the console.
Thanks,
-Mike
String.Join(result.Select(d => d.ToString("0.00"))
Custom Numeric Format Strings
Console class effectively buffers all received data, so multiple Console.Write calls actually don't reduce permormance. Also you don't have to get all the text in one huge piece. So my answer is:
IEnumerable<double> result = new double[] { 1.1234, 2.2345, 3.3456 };
foreach (double item in result)
Console.Write ("{0},", item.ToString("0.00"));
Console.WriteLine ();
Explicit double.ToString call allows to avoid unnecessary boxing. But I suggest you to compare performance in both ways before using more complicated one.
Also note that in some cultures a comma is already used as fractional separator.
Related
I have a string with the format 00-00 and I want to increment it to 00-01.
Currently I am using Split() but I have the feeling that my approach is not really best practice.
I don't have to worry about edge cases and just want to know if there is an elegant solution.
Thanks
Linq approach without edge cases like 00-99 or 99-99
string input ="07-01";
string result = string.Join("-", input.Split('-')
.Select(int.Parse)
.Select((x, i) => (i == 1 ? ++x : x).ToString("00")));
Your method of utilizing string.Split() would be my suggestion too.
However, I'm wondering if you are repeatedly incrementing that number. if this is a one time action, then I agree with using the split method.
If you are continually incrementing this number (e.g. as a counter), you will start noticing that it takes more resources to do string operations (split) and conversions (string to int, int to string); compared to incrementing the value of the integer.
In this case, I would advocate that you keep the integer value in memory, and keep using that to generate your output string, instead of always having to start from scratch.
However, the latter suggestion only applies if you keep incrementing the same values. Your question did not specify that that is the case.
I'm trying to format some doubles properly so that they will display properly for my uses (I'm building a statement in Devexpress, so I'm working with a lot of numbers).
Here are the basic formatting rules I'd like to have happen:
1000.2 -> 1,000.20
1000 -> 1,000
1000.22 -> 1,000.22
Is this possible using string formatting in C#? I've tried the following, but not been able to achieve my goal:
#,#.## - gives me 1,000.2 for the first value
#,#.#0 - gives me 1,000.00 for the second value
#,#.00 - gives me 1,000.00 for the second value
EDIT: Some more information. DevExpress gives me the ability to use string formatting to set up the values after they've been bound to the report. We're doing it at report time (and not at calculation time in the behind the scenes code) because we use the Sum function within the tables that DevExpress offers us. The reason we do THAT is so that we can minimize calls to our database by doing one large pull of data, then using that table over and over again in the statement and filtering based on the restrictions within.
EDIT EDIT:
Based on the feedback I've receieved here in the comments, it's not possible to perform the formatting I'd like to do with only providing a string format; I would need to insert some code either when I provide the data to the report (and then remove any and all formatting from the report) and perform all summing functions at the code level (to ensure that the sum values have the expected decimal places), or I would need to accept .00 at the end of, for example, some amount of yen (100 JPY would never be represented as 100.00 JPY, as an example).
This is a bit of an esoteric case, but it's good to know!
You can use string formatting coupled to a simple if condition. To shorten it's use, you can also make it an Extension method. It can look like this :
public static string FormatConditionnaly(this double input)
{
return input % 1 == 0 ? input.ToString("#,0") : input.ToString("#,0.00");
}
Basically, if you number does not contain any decimals (the % 1 == 0 check), you format it without decimals. If it fails the check, you add the two zeroes.
It is used like that :
const double flatNumber = 1000;
string result1 = flatNumber.FormatConditionnaly(); //1,000
const double numberWithDecimals = 1000.5;
string result2 = numberWithDecimals.FormatConditionnaly(); //1,000,50
Bit of a hack but you can give this a try:
s = String.Format("{0:N2}", 1000).Replace(".00", "");
Use the "N" format specifier as the format string when you call ToString(); See here
For example:
int intValue = 123456789;
Console.WriteLine(intValue.ToString("N2",
CultureInfo.InvariantCulture).Replace(".00", "");
You can customize group sizes etc. as needed.
Why don't you format the values before binding to DevExpress control using plain old C# (Assuming you are doing a bind, as you have not given sufficient details.)
In c# the Math.Round() should do the trick.
Example Math.Round(doubleValue,2) where the second parameter is the number of decimal places.
EDIT:
#,##0.00
I Do not have DevExpress controls to test my solution but I did find http://documentation.devexpress.com/#windowsforms/CustomDocument1498 online (not sure if you see it already).
It seems you can use the Number or Currency masks.
Also take a look at the Zero Placeholder under the custom section. based on the description, '0' is filled where the user has not supplied a value.
example: 123.4 --> 123.40
If the string that you're trying to format is in an XRTableCell of an XtraReport instance, you can handle the BeforePrint event on that cell to format its text. This event is triggered anytime that the report is rendered. Call GetCurrentColumnValue to retrieve the value that you want to format, use any of the code methods from the previous answers that will work for you, and then set that cell's text with your formatted string. Using #dweeberly's answer:
private void OnBeforePrint(object sender, PrintEventArgs e)
{
object value = this.GetCurrentColumnValue("YourField");
if (value != null)
{
yourCell.Text = String.Format("{0:N2}", value.ToString()).Replace(".00", "");
}
}
Based on the feedback I've receieved here in the comments, it's not possible to perform the formatting I'd like to do with only providing a string format; I would need to insert some code either when I provide the data to the report (and then remove any and all formatting from the report) and perform all summing functions at the code level (to ensure that the sum values have the expected decimal places), or I would need to accept .00 at the end of, for example, some amount of yen (100 JPY would never be represented as 100.00 JPY, as an example).
This is a bit of an esoteric case, but it's good to know!
In C# I have an array of double (double[] I mean)
I want to round all values to two decimal places in C#.
One solution is to do this with foreach() and Math.Round() functions
but the array is very large (1.000.000 to 10.000.000 values)
Instead of foreach, is there a more efficient solution?
Instead of foreach, a more efficient solution?
Nope. Fundamentally, if you want to round all the values, you've got to round all the values. There's no magic that will make that simpler.
Of course, if you're only going to access a few of the values, you could potentially redesign your code to lazily round on access - or even on display - but if you really need the rounded versions of all the values, there's nothing that will make that faster than an O(n) operation.
You could do it in parallel as noted in other answers, which may well make it faster - but it will simultaneously be less efficient than a single-threaded approach. (You'll end up doing more work, because of the coordination involved - but you'll still get it done faster overall, probably.)
You haven't said anything about why you want to round these values though - usually, you should only round values at the point of display. Are you really sure you need to round them before then? What do the values represent? (If they're financial values, you should strongly consider decimal instead of double.)
You can try Parallel.Foreach and thread it
While there is still an operation per item, the operations are not atomic so you can do this.
To do it in a multi-threaded way:
Parallel.For(0, arr.Length, i => arr[i] = Math.Round(arr[i], 2));
I don't think there is any solution which does not include some kind of loop. You could use LINQ:
array = array.Select(v => Math.Round(v, 2)).ToArray();
but it will be even slower then your custom for loop, because instead of modifying the array in place, it will create new one with new values.
To make your loop faster, you can split it into parts and run simultaneously, using TPL.
Any solution will eventually devolve into a loop. Though you may write nicely as a Linq statement:
rounds = mean.Select(x=>Math.Round(x,2));
If you have multiple processors then a potentially faster solution would be to use Parallel.Foreach, though you'd have to test it to see if it actually is.
Yeah, you can use Parallel.ForEach.
List<Double> values;
//fill list
ConcurrentBag<Double> rounded = new ConcurrentBag<Double>();
Parallel.ForEach(
values,
value =>
{
rounded.Add(/*value rounded to 2 decimal places*/);
});
I have a exponential number : 4.65661287307739E-10
When I round it off using JavaScript, it gets converted as 5. I use following code
var roundFormattedNumber = function (n) {
var val = parseFloat(n.replace(/[^0-9.]/g, '')).toFixed(0);
Ext.util.Format.thousandSeparator = ',';
Ext.util.Format.decimalSeparator = '.';
return Ext.util.Format.number(val, '0,000');
};
When I try to first parse this number into decimal using C# I get : 0.000000000465661287307739M
decimal amount;
decimal.TryParse("4.65661287307739E-10", NumberStyles.Any, CultureInfo.InvariantCulture, out amount);
If I round off this value using C# result would be different as compared to JavaScript result.
Why there is a difference? Which result it correct?
Please suggest.
Thank you
When I round it off using JavaScript, it gets converted as 5.
That's not JavaScript, that's your code. You're removing everything from the string that isn't a digit or a .:
var val = parseFloat(n.replace(/[^0-9.]/g, '')).toFixed(0);
// -------------------^^^^^^^^^^^^^^^^^^^^^^^^
...so you're turning
4.65661287307739E-10
into
4.6566128730773910
and then parsing that, which naturally gives you a completely different number from 4.65661287307739E-10. There's no need to do that, JavaScript's parseFloat can interpret E-notation.
Whereas in your C# code, you're actually providing the E-notation number to the TryParse function.
Why there is a difference?
Because in the one case you're removing really important information from the string before asking JavaScript to parse it.
Which result it correct?
The C# one (although I have no idea why there's an M at the end of it).
I need help on an algorithm. I have randomly generated numbers with 6 digits. Like;
123654
109431
There are approximately 1 million of them saved in a file line by line. I have to filter them according to the rule I try to describe below.
Take a number, compare it to all others digit by digit. If a number comes up with a digit with a value of bigger by one to the compared number, then delete it. Let me show it by using numbers.
Our number is: 123456
Increase the first digit with 1, so the number becomes: 223456. Delete all the 223456s from the file.
Increase the second digit by 1, the number becomes: 133456. Delete all 133456s from the file, and so on...
I can do it just as I describe but I need it to be "FAST".
So can anyone help me on this?
Thanks.
First of all, since it is around 1Million you had better perform the algorithm in RAM, not on Disk, that is, first load the contents into an array, then modify the array, then paste the results back into the file.
I would suggest the following algorithm - a straightforward one. Precalculate all the target numbers, in this case 223456, 133456, 124456, 123556, 123466, 123457. Now pass the array and if the number is NOT any of these, write it to another array. Alternatively if it is one of these numbers delete it(recommended if your data structure has O(1) remove)
This algorithm will keep a lot of numbers around in memory, but it will process the file one number at a time so you don't actually need to read it all in at once. You only need to supply an IEnumerable<int> for it to operate on.
public static IEnumerable<int> FilterInts(IEnumerable<int> ints)
{
var removed = new HashSet<int>();
foreach (var i in ints)
{
var iStr = i.ToString("000000").ToCharArray();
for (int j = 0; j < iStr.Length; j++)
{
var c = iStr[j];
if (c == '9')
iStr[j] = '0';
else
iStr[j] = (char)(c + 1);
removed.Add(int.Parse(new string(iStr)));
iStr[j] = c;
}
if (!removed.Contains(i))
yield return i;
}
}
You can use this method to create an IEnumerable<int> from the file:
public static IEnumerable<int> ReadIntsFrom(string path)
{
using (var reader = File.OpenText(path))
{
string line;
while ((line = reader.ReadLine()) != null)
yield return int.Parse(line);
}
}
Take all the numbers from the file to an arrayList, then:
take the number of threads as the number of digits
increment the first digit on the number in first thread, second in the second thread and then compare it with the rest of the numbers,
It would be fast as it will undergo by parallel processing...
All the suggestions (so far) require six comparisons per input line, which is not necessary. The numbers are coming in as strings, so use string comparisons.
Start with #Armen Tsirunyan's idea:
Precalculate all the target numbers,
in this case 223456, 133456, 124456,
123556, 123466, 123457.
But instead of single comparisons, make that into a string:
string arg = "223456 133456 124456 123556 123466 123457";
Then read through the input (either from file or in memory). Pseudocode:
foreach (string s in theBigListOfNumbers)
if (arg.indexOf(s) == -1)
print s;
This is just one comparison per input line, no dictionaries, maps, iterators, etc.
Edited to add:
In x86 instruction set processors (not just the Intel brand), substring searches like this are very fast. To search for a character within a string, for example, is just one machine instruction.
I'll have to ask others to weigh in on alternate architectures.
For starters, I would just read all the numbers into an array.
When you are finally done, rewrite the file.
It seems like the rule you're describing is for the target number abdcef you want to find all numbers that contain a+1, b+1, c+1, d+1, e+1, or f+1 in the appropriate place. You can do this in O(n) by looping over the lines in the file and comparing each of the six digits to the digit in the target number if no digits match, write the number to an output file.
This sounds like a potential case for a multidimensional array, and possibly also unsafe c# code so that you can use pointer math to iterate through such a large quantity of numbers.
I would have to dig into it further, but I would also probably use a Dictionary for non-linear lookups, if you are comparing numbers that aren't in sequence.
How about this. You process numbers one by one. Numbers will be stored in hash tables NumbersOK and NumbersNotOK.
Take one number
If it's not in NumbersNotOK place it in a Hash of NumbersOK
Get it's variances of single number increments in hash - NumbersNotOK.
Remove all of the NumbersOK members if they match any of the variances.
Repeat from 1, untill end of file
Save the NumbersOK to the file.
This way you'll pass the list just once. The hash table is made just for this kind of purposes and it'll be very fast (no expensive comparison methods).
This algorithm is not in full, as it doesn't handle when there are some numbers repeating, but it can be handled with some tweaking...
Read all your numbers from the file and store them in a map where the number is the key and a boolean is the value signifying that the value hasn't been deleted. (True means exists, false means deleted).
Then iterate through your keys. For each key, set the map to false for the values you would be deleting from the list.
Iterate through your list one more time and get all the keys where the value is true. This is the list of remaining numbers.
public List<int> FilterNumbers(string fileName)
{
StreamReader sr = File.OpenTest(fileName);
string s = "";
Dictionary<int, bool> numbers = new Dictionary<int, bool>();
while((s = sr.ReadLine()) != null)
{
int number = Int32.Parse(s);
numbers.Add(number,true);
}
foreach(int number in numbers.Keys)
{
if(numbers[number])
{
if(numbers.ContainsKey(100000+number))
numbers[100000+number]=false;
if(numbers.ContainsKey(10000+number))
numbers[10000+number]=false;
if(numbers.ContainsKey(1000+number))
numbers[1000+number]=false;
if(numbers.ContainsKey(100+number))
numbers[100+number]=false;
if(numbers.ContainsKey(10+number))
numbers[10+number]=false;
if(numbers.ContainsKey(1+number))
numbers[1+number]=false;
}
}
List<int> validNumbers = new List<int>();
foreach(int number in numbers.Keys)
{
validNumbers.Add(number);
}
return validNumbers;
}
This may need to be tested as I don't have a C# compiler on this computer and I'm a bit rusty. The algorithm will take a bit of memory bit it runs in linear time.
** EDIT **
This runs into problems whenever one of the numbers is 9. I'll update the code later.
Still sounds like a homework question... the fastest sort on a million numbers will be n log(n) that is 1000000log(1000000) that is 6*1000000 which is the same as comparing 6 numbers to each of the million numbers. So a direct comparison will be faster than sort and remove, because after sorting you still have to compare to remove. Unless, ofcourse, my calculations have entirely missed the target.
Something else comes to mind. When you pick up the number, read it as hex and not base 10. then maybe some bitwise operators may help somehow.
Still thinking on what can be done using this. Will update if it works
EDIT: currently thinking on the lines of gray code. 123456 (our original number) and 223456 or 133456 will be off only by one digit and a gray code convertor will catch it fast. It's late night here, so if someone else finds this useful and can give a solution...