Displaying bandwidth speed in a user-friendly format - c#

I'm looking for a string conversion method that will receive an input of KB/s and converts it to the easiest readable format possible.
e.g. 1500 b/s = 1.46 Kb/s
e.g. 1500 Kb/s = 1.46 Mb/s
e.g. 1500 Mb/s = 1.46 Gb/s
Thanks

Try this:
var ordinals = new [] {"","K","M","G","T","P","E"};
long bandwidth = GetTheBandwidthInBitsPerSec();
decimal rate = (decimal)bandwidth;
var ordinal = 0;
while(rate > 1024)
{
rate /= 1024;
ordinal++;
}
output.Write(String.Format("Bandwidth: {0} {1}b/s",
Math.Round(rate, 2, MidpointRounding.AwayFromZero),
ordinals[ordinal]));
The ordinals (prefixes) available here are Kilo-, Mega-, Giga-, Tera-, Peta-, Exa-. If you really think your program will be around long enough to see Zettabit and Yottabit network bandwidths, by all means throw the Z and Y prefix initials into the array.
To convert from one formatted string to the other, split on spaces, look at the term that will be the number, and then search the term immediately following for one of the prefixes. Find the index of the ordinal in the array, add 1, and multiply by 1024 that many times to get to bits per second:
var bwString= GetBandwidthAsFormattedString(); //returns "Bandwidth: 1056 Kb/s";
var parts = String.Split(bwString, " ");
var number = decimal.Parse(parts[1]);
var ordinalChar = parts[2].First().ToString();
ordinalChar = ordinalChar = "b" ? "" : ordinalChar;
var ordinal = ordinals.IndexOf(ordinalChar)
... //previous code, substituting the definition of ordinal

I made this code in about 30 secondes, so there is no validation, but I think it does what you want
string vInput = "1500 Kb/s";
string[] tSize = new string[] { "b/s", "Kb/s", "Mb/s", "Gb/s" };
string[] tSplit = vInput.Split(new string[] {" "}, StringSplitOptions.RemoveEmptyEntries);
double vSpeed = Double.Parse(tSplit[0]) / 1024.0;
vSpeed = Math.Round(vSpeed, 2);
int i = 0;
for(i = 0; i < tSize.Length;++i)
{
if(tSplit[1].StartsWith(tSize[i]))
{
break;
}
}
string vOutput = vSpeed.ToString() + " " + tSize[i+1];

Related

How do you do a string split with 2 chars counts in C#?

I know how to do a string split if there's a letter, number, that I want to replace.
But how could I do a string.Split() by 2 char counts without replacing any existing letters, number, etc...?
Example:
string MAC = "00122345"
I want that string to output: 00:12:23:45
You could create a LINQ extension method to give you an IEnumerable<string> of parts:
public static class Extensions
{
public static IEnumerable<string> SplitNthParts(this string source, int partSize)
{
if (string.IsNullOrEmpty(source))
{
throw new ArgumentException("String cannot be null or empty.", nameof(source));
}
if (partSize < 1)
{
throw new ArgumentException("Part size has to be greater than zero.", nameof(partSize));
}
return Enumerable
.Range(0, (source.Length + partSize - 1) / partSize)
.Select(pos => source
.Substring(pos * partSize,
Math.Min(partSize, source.Length - pos * partSize)));
}
}
Usage:
var strings = new string[] {
"00122345",
"001223453"
};
foreach (var str in strings)
{
Console.WriteLine(string.Join(":", str.SplitNthParts(2)));
}
// 00:12:23:45
// 00:12:23:45:3
Explanation:
Use Enumerable.Range to get number of positions to slice string. In this case its the length of the string + chunk size - 1, since we need to get a big enough range to also fit leftover chunk sizes.
Enumerable.Select each position of slicing and get the startIndex using String.Substring using the position multiplied by 2 to move down the string every 2 characters. You will have to use Math.Min to calculate the smallest size leftover size if the string doesn't have enough characters to fit another chunk. You can calculate this by the length of the string - current position * chunk size.
String.Join the final result with ":".
You could also replace the LINQ query with yield here to increase performance for larger strings since all the substrings won't be stored in memory at once:
for (var pos = 0; pos < source.Length; pos += partSize)
{
yield return source.Substring(pos, Math.Min(partSize, source.Length - pos));
}
You can use something like this:
string newStr= System.Text.RegularExpressions.Regex.Replace(MAC, ".{2}", "$0:");
To trim the last colon, you can use something like this.
newStr.TrimEnd(':');
Microsoft Document
Try this way.
string MAC = "00122345";
MAC = System.Text.RegularExpressions.Regex.Replace(MAC,".{2}", "$0:");
MAC = MAC.Substring(0,MAC.Length-1);
Console.WriteLine(MAC);
A quite fast solution, 8-10x faster than the current accepted answer (regex solution) and 3-4x faster than the LINQ solution
public static string Format(this string s, string separator, int length)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.Length; i += length)
{
sb.Append(s.Substring(i, Math.Min(s.Length - i, length)));
if (i < s.Length - length)
{
sb.Append(separator);
}
}
return sb.ToString();
}
Usage:
string result = "12345678".Format(":", 2);
Here is a one (1) line alternative using LINQ Enumerable.Aggregate.
string result = MAC.Aggregate("", (acc, c) => acc.Length % 3 == 0 ? acc += c : acc += c + ":").TrimEnd(':');
An easy to understand and simple solution.
This is a simple fast modified answer in which you can easily change the split char.
This answer also checks if the number is even or odd , to make the suitable string.Split().
input : 00122345
output : 00:12:23:45
input : 0012234
output : 00:12:23:4
//The List that keeps the pairs
List<string> MACList = new List<string>();
//Split the even number into pairs
for (int i = 1; i <= MAC.Length; i++)
{
if (i % 2 == 0)
{
MACList.Add(MAC.Substring(i - 2, 2));
}
}
//Make the preferable output
string output = "";
for (int j = 0; j < MACList.Count; j++)
{
output = output + MACList[j] + ":";
}
//Checks if the input string is even number or odd number
if (MAC.Length % 2 == 0)
{
output = output.Trim(output.Last());
}
else
{
output += MAC.Last();
}
//input : 00122345
//output : 00:12:23:45
//input : 0012234
//output : 00:12:23:4

How to find text between two tabs

I have a file that looks similar like the following:
Tomas | Nordstrom | Sweden | Europe | World
(the character "|" in the above line represents a tab, new column)
Now I want a string containing only the text in the 4th column.
I have succeeded to find characters in a certain spot in the line. But that spot changes according to the number och characters in each column.
I could really need some nice input on this.
Thanks in advance.
/Tomas
This can be done using the Split method like this:
string s = "Tomas|Nordstrom|Sweden|Europe|World";
string[] stringArray = s.Split( new string[] { "|" }, StringSplitOptions.None );
Console.WriteLine( stringArray[3] );
This will print out "Europe", because that is located at index 3 in stringArray.
Edit:
The same can be achieved using Regex like this:
string[] stringRegex = Regex.Split( s, #"\|+" );
Basic algorithm would be iterating characters, until n-1 tabs found, then take chars up to the next tab or the end of string.
Depending on requirements, if performance is critical, you might need to implement a scanning algorithm manually.
You might be surprising how slow is string splitting. Well - it's not not by itself, but the overall approach requires:
Scanning to the end of the string
Creation of all of the split parts on heap
Collecting garbage
Consider following benchmark of the two approaches:
void Main()
{
string source = "Tomas\tNordstrom\tSweden\tEurope\tWorld";
var sw = Stopwatch.StartNew();
string result = null;
var n = 100000000;
for (var i = 0; i < n; i++)
{
result = FindBySplitting(source);
}
sw.Stop();
var splittingNsop = (double)sw.ElapsedMilliseconds / n * 1000000.0;
Console.WriteLine("Splitting. {0} ns/op",splittingNsop);
Console.WriteLine(result);
sw.Restart();
for (var i = 0; i < n; i++)
{
result = FindByScanning(source);
}
sw.Stop();
var scanningNsop = (double)sw.ElapsedMilliseconds / n * 1000000.0;
Console.WriteLine("Scanning. {0} ns/op",
scanningNsop);
Console.WriteLine(result);
Console.WriteLine("Scanning over splitting: {0}", splittingNsop / scanningNsop);
}
string FindBySplitting(string s)
{
return s.Split('\t')[3];
}
string FindByScanning(string s)
{
int l = s.Length, p = 0, q = 0, c = 0;
while (c++ < 4 - 1)
while (p < l && s[p++] != '\t')
;
for (q = p; q < l && s[q] != '\t'; q++)
;
return s.Substring(p, q - p);
}
Scanning algorithm implemented in pure C# outperforms the splitting one implemented on the low level by a factor of 4.6 on my laptop:
Splitting. 174.81 ns/op
Europe
Scanning. 37.58 ns/op
Europe
Scanning over splitting: 4.65167642362959

Reading .txt file into an array

I need to be able to read a text file into an array instead of inputting all the values myself.
The text file reads as:
8.7
9.3
7.9
6.4
9.6
8.0
8.8
9.1
7.7
9.9
5.8
6.9
The main purpose of the program is to read scores from a data file, store them in an array, and calculate the highest, lowest, total and average of the 12 scores.
The text file is stored in the Debug folder of the project.
This is what I've done so far:
Console.WriteLine("Numbers in the list: " + scores.Length);
//highest number
double high = scores[0];
for (int index = 1; index < scores.Length; index++)
{
if (scores[index] > high)
{
high = scores[index];
}
}
Console.WriteLine("Highest number = " + high);
//lowest number
double low = scores[0];
for (int index = 1; index < scores.Length; index++)
{
if (scores[index] < low)
{
low = scores[index];
}
}
Console.WriteLine("lowest number = " + low);
//average of the scores
double total = 0;
double average = 0;
for (int index = 0; index < scores.Length; index++)
{
total = total + scores[index];
}
average = (double)total / scores.Length;
Console.WriteLine("Total = " + total);
Console.WriteLine("Average = " + average.ToString("N2"));
Console.ReadKey();
}
}
}
You have no code in place for reading a file, or writing a file so that will be your problem. I suggest you start with looking at: StreamReader Class (MSDN).
Then you will probably want to look at the following: String.Split Method (MSDN)
To make the program a bit more dynamic you possible want to consider looking at this:
Application.ExecutablePath Property (MSDN)
Enviroment.GetFolderPath Method (MSDN) (This allows you to store data in better locations)
^^^^Original Response above^^^^^
Another option you could consider is described in a lot of detail here:
Working with Files - Code Project Article
You can use File.ReadLines method to read the lines lazily (means doesn't load all the lines to memory at once) from your file and Select method to take each line and parse it to double:
var values = File.ReadLines("path")
.Select(line => double.Parse(line))
.ToArray();
Then you can use Max,Min,Average methods from LINQ to get highest,lowest number and the average.
All of this can be writen easier :
using System;
using System.IO;
using System.Linq;
String path = #"MyFolder\myfile.txt"; // path for your file
// read the file
String[] lines = File.ReadAllLines(path);
// convert data in Doubles
Double[] data = Array.ConvertAll(lines, Double.Parse);
// use Linq to get what you want (min, max, total, average, ...)
Double low = data.Min();
Double high = data.Max();
Double total = data.Sum();
Double average = data.Average();
var scores = File.ReadAllLines("scores.txt").Select(x => Double.Parse(x)).ToArray();
var numbers = File.ReadAllLines(#"C:\numbers.txt")
.Select(n => double.Parse(n));
var max = numbers.Max();
var min = numbers.Min();
var sum = numbers.Sum();
var avg = numbers.Average();

Get a range from two integers

string num = db.SelectNums(id);
string[] numArr = num.Split('-').ToArray();
string num contain for an example "48030-48039";
string[] numArr will therefor contain (48030, 48039).
Now I have two elements, a high and low. I now need to get ALL the numbers from 48030 to 48039. The issue is that it has to be string since there will be telephone numbers with leading zeroes now and then.
Thats why I cannot use Enumerable.Range().ToArray() for this.
Any suggestions? The expected result should be 48030, 48031, 48032, ... , 48039
This should work with your leading zero requirement:
string num = db.SelectNums(id);
string[] split = num.Split('-');
long start = long.Parse(split[0]);
long end = long.Parse(split[1]);
bool includeLeadingZero = split[0].StartsWith("0");
List<string> results = new List<string>();
for(int i = start; i <= end; i++)
{
string result = includeLeadingZero ? "0" : "";
result += i.ToString();
results.Add(result);
}
string[] arrayResults = results.ToArray();
A few things to note:
It assumes your input will be 2 valid integers split by a single hyphen
I am giving you a string array result, personally I would prefer to work with a List<int> in the end
If the first number contains a single leading zero, then all results will contain a single leading zero
It uses long to cater for longer numbers, beware that the max number that will parse is 9,223,372,036,854,775,807, you could double this value (not length) by using ulong
Are you saying this?
int[] nums = new int[numArr.Length];
for (int i = 0; i < numArr.Length; i++)
{
nums[i] = Convert.ToInt32(numArr[i]);
}
Array.Sort(nums);
for (int n = nums[0]; n <= nums[nums.Length - 1]; n++)
{
Console.WriteLine(n);
}
here link
I am expecting your string always have valid two integers, so using Parse instead TryParse
string[] strList = "48030-48039".Split('-').ToArray();
var lst = strList.Select(int.Parse).ToList();
var min = lst.OrderBy(l => l).FirstOrDefault();
var max = lst.OrderByDescending(l => l).FirstOrDefault();
var diff = max - min;
//adding 1 here otherwise 48039 will not be there
var rng = Enumerable.Range(min,diff+1);
If you expecting invalid string
var num = 0;
var lst = (from s in strList where int.TryParse(s, out num) select num).ToList();
This is one way to do it:
public static string[] RangeTest()
{
Boolean leadingZero = false;
string num = "048030-48039"; //db.SelectNums(id);
if (num.StartsWith("0"))
leadingZero = true;
int min = int.Parse(num.Split('-').Min());
int count = int.Parse(num.Split('-').Max()) - min;
if (leadingZero)
return Enumerable.Range(min, count).Select(x => "0" + x.ToString()).ToArray();
else
return Enumerable.Range(min, count).Select(x => "" + x.ToString()).ToArray(); ;
}
You can use string.Format to ensure numbers are formatted with leading zeros. That will make the method work with arbitrary number of leading zeros.
private static string CreateRange(string num)
{
var tokens = num.Split('-').Select(s => s.Trim()).ToArray();
// use UInt64 to allow huge numbers
var start = UInt64.Parse(tokens[0]);
var end = UInt64.Parse(tokens[1]);
// if your start number is '000123', this will create
// a format string with 6 zeros ('000000')
var format = new string('0', tokens[0].Length);
// use StringBuilder to make GC happy.
// (if only there was a Enumerable.Range<ulong> overload...)
var sb = new StringBuilder();
for (var i = start; i <= end; i++)
{
// format ensures that your numbers are padded properly
sb.Append(i.ToString(format));
sb.Append(", ");
}
// trim trailing comma after the last element
if (sb.Length >= 2) sb.Length -= 2;
return sb.ToString();
}
Usage example:
// prints 0000012, 0000013, 0000014
Console.WriteLine( CreateRange("0000012-0000014") );
Three significant issues were brought up in comments:
The phone numbers have enough digits to exceed Int32.MaxValue so
converting to int isn't viable.
The phone numbers can have leading zeros (presumeably for some
international calling?)
The possible range of numbers can theoretically exceed the maximum size of an array (which may have memory issues, and I think may not be represented as a string)
As such, you may need to use long instead of int, and I would suggest using deferred execution if needed for very large ranges.
public static IEnumerable<string> EnumeratePhoneNumbers(string fromAndTo)
{
var split = fromAndTo.Split('-');
return EnumeratePhoneNumbers(split[0], split[1]);
}
public static IEnumerable<string> EnumeratePhoneNumbers(string fromString, string toString)
{
long from = long.Parse(fromString);
long to = long.Parse(toString);
int totalNumberLength = fromString.Length;
for (long phoneNumber = from; phoneNumber <= to; phoneNumber++)
{
yield return phoneNumber.ToString().PadLeft(totalNumberLength, '0');
}
}
This assumes that the padded zeros are already included in the lower bound fromString text. It will iterate and yield out numbers as you need them. This can be useful if you're churning out a lot of numbers and don't need to fill up memory with them, or if you just need the first 10 or 100. For example:
var first100Numbers =
EnumeratePhoneNumbers("0018155500-7018155510")
.Take(100)
.ToArray();
Normally that range would produce 7 billion results which cannot be stored in an array, and might run into memory issues (I'm not even sure if it can be stored in a string); by using deferred execution, you only create the 100 needed.
If you do have a small range, you can still join up your results into a string as you desired:
string numberRanges = String.Join(", ", EnumeratePhoneNumbers("0018155500-0018155510"));
And naturally you can put this array creation into your own helper method:
public static string GetPhoneNumbersListing(string fromAndTo)
{
return String.Join(", ", EnumeratePhoneNumbers("0018155500-0018155510"));
}
So your usage would be:
string numberRanges = GetPhoneNumbersListing("0018155500-0018155510");
A complete solution inspired by the answer by #Dan-o:
Inputs:
Start: 48030
End: 48039
Digits: 6
Expected String Output:
048030, 048031, 048032, 048033, 048034, 048035, 048036, 048037, 048038, 048039
Program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class Program
{
public static void Main()
{
int first = 48030;
int last = 48039;
int digits = 6;
Console.WriteLine(CreateRange(first, last, digits));
}
public static string CreateRange(int first, int last, int numDigits)
{
string separator = ", ";
var sb = new StringBuilder();
sb.Append(first.ToString().PadLeft(numDigits, '0'));
foreach (int num in Enumerable.Range(first + 1, last - first))
{
sb.Append(separator + num.ToString().PadLeft(numDigits, '0'));
}
return sb.ToString();
}
}
For Each item In Enumerable.Range(min, count).ToArray()
something = item.PadLeft(5, "0")
Next

Avg,max,min,sum from string?

Hello i got array of string, and they are durations made by myself in format H:M:S:MS
Example strings:
0:0:4:410
0:0:1:425
0:0:1:802
0:0:1:509
0:0:1:674
0:0:1:628
0:0:2:76
How can i sum/avg/min/max values of these items in arraylist?
Arraylist name is arrayLL.
I'm new in c# so hope someone will show me how to work with strings.
The function that adds to array is:
if (Session["DT"].ToString() != "")
{
TimeSpan ts = ((DateTime)Session["DT2"]).Subtract((DateTime)Session["DT"]);
Session["TimeL"] = ts.Hours.ToString() + ":"
+ ts.Minutes.ToString() + ":"
+ ts.Seconds.ToString() + ":"
+ ts.Milliseconds.ToString();
}
Assuming the numbers represent hours, minutes, seconds, and milliseconds you can try the following:
// Empty list you will populate:
List<int> durationsInMilliseconds = new List<int>();
// Loop through your existing data, and calculate all
// durations into milliseconds:
foreach (string word in yourDurationArray)
{
string[] values = s.Split(':');
int hoursAsMilliseconds = Integer.parse(values[0]) * 60 * 60 * 1000;
int minutesAsMilliseconds = Integer.parse(values[1]) * 60 * 1000;
int secondsAsMilliseconds = Integer.parse(values[2]) * 1000;
int sumDurationAsMilliseconds = hoursAsMilliseconds +
minutesAsMilliseconds +
secondsAsMilliseconds +
Integer.parse(values[3]);
durationsInMilliseconds.add(sumDurationAsMilliseconds);
}
Now you should have a list of type Integer (durationsInMilliseconds) which contains the numbers in a single comparable format. With this, you should be able to do whichever calculations you need.
(PS: If you need the result in the same format as the original input-data, you will have to add an operation for calculating back from MS into hours, minutes and seconds..)
Since i guess they are Durations so i you should do this
var enu_ts = yourvariable.OfType<string>().Select(x =>
TimeSpan.Parse(x, #"h\:m\:s\:fff", CultureInfo.InvariantCulture));
Max
var max = enu_ts.Max().ToString();
Min
var max = enu_ts.Min().ToString();
foreach(string s in dateString)
{
spanList[i] = TimeSpan.Parse(s);
total=total.Add(spanList[i++]);
}
Response.Write("Max TimeSpan:"+spanList.Max<TimeSpan>());
Response.Write("Min TimeSpan:" + spanList.Min<TimeSpan>());
Response.Write("Total Sum of TimeSpan:"+total);

Categories

Resources