Retrieve values in nested link with C# - c#

I have a nested string list and I am trying to save each item in specific variable.
I tried this way but I got this result with duplication of each one:
one one
Two Two Two Two Two Two Two
three three three three three three three
four four four four four four four
five five five five five five five
six six six six six six six
seven seven seven seven seven seven
string argp;
string arg0;
string arg1;
string arg2;
string arg3;
string arg4;
string arg5;
string arg6;
string arguments;
List<List<string>> myList = new List<List<string>>();
myList.Add(new List<string> { #"one", "two", "three", "four", "five", "six", "seven" });
myList.Add(new List<string> { #"one", "two", "three", "four", "five", "six", "seven" });
for (var i = 0; i < myList.Count; i++)
{
argp = myList[i][0];
for (var j = 0; j < myList[i].Count; j++)
{
arg0 = myList[i][j];
// = "localhost";
arg1 = myList[i][j];
arg2 = myList[i][j];
arg3 = myList[i][j];
arg4 = myList[i][j];
arg5 = myList[i][j];
arg6 = myList[i][j];
arguments = myList[i][j] + " " + myList[i][j] + " " + arg2 + " " + arg3 + " " + arg4 + " " + arg5 + " " + arg6;
Console.WriteLine(arguments);
}
Console.WriteLine("==============");
}

You don't need the inner loop:
for (var i = 0; i < myList.Count; i++)
{
var list = myList[i]; // todo - check if enough elements?
arg0 = list[0];
arg1 = list[1];
arg2 = list[2];
arg3 = list[3];
arg4 = list[4];
arg5 = list[5];
arg6 = list[6];
Console.WriteLine(string.Join(" ", arg0, arg1, ...));
Console.WriteLine("==============");
}
Note that this will overwrite argX's in every iteration, if the goal is to combine arguments positionally you can do something like arg0 += " " + list[0]; (as a quick and dirty approach, if a lot of lists are expected then better to consider using something like StringBuilder).
If the goal is to just output the arguments you can do it much easier with foreach and string.Join:
foreach (var list in myList)
{
Console.WriteLine(string.Join(" ", list));
Console.WriteLine("==============");
}

Related

Algorithm confusion regarding the number conversion in C#

I am following a tutorial regarding converting an integer number into a spoken-word equivalent in C#.
I am getting a bit confused about the three digit rule.
// Single-digit and small number names
private static string[] smallNumbers = new string[]
{
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen"
};
// Tens number names from twenty upwards
private static string[] tens = new string[]
{
"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy",
"eighty", "ninety"
};
// Scale number names for use during recombination
private static string[] scaleNumbers = new string[]
{
"", "thousand", "million", "billion", "trillion",
"quadrillion", "quintillion"
};
public static string ToWords(this BigInteger number)
{
if (number == 0)
{
return "zero";
}
int[] digitGroups = new int[groups];
// Ensure a positive number to extract from
var positive = BigInteger.Abs(number);
// Extract the three-digit groups
for (int i = 0; i < groups; i++)
{
digitGroups[i] = (int)(positive % 1000);
positive /= 1000;
}
//The rest of the code..
}
I am assuming now we are converting a number and its value is 25111.
In the for-loop function, the return value of (int)(positive % 1000) should be 111. The 111 does not match any elements in digitalGroups array.
I don't quite get it, can someone explain it to me? Thanks in advance.
The code you are showing us is not matching but rather assigning the value 111 to the first item of the digitGroupsArray.
How many items has digitGroupsArray? I don't know, it depends on the 'groups' variable value, which we can't see in the code excerpt.
Here:
int[] digitGroups = new int[groups];
you're creating a new empty integer array called digitGroups with the length of (int) 'group' value.
While this,
for (int i = 0; i < groups; i++)
{
digitGroups[i] = (int)(positive % 1000);
positive /= 1000;
}
is a cylce, an iteration. And note that each time the 'positive' variable gets divided by 1000 (like positive = positive / 1000).
The result will be like this:
digitGroups[0] = (int)(25111 % 1000) // first item of digitGroupsarray
'positive' gets divided (25111 / 1000) next time will be 25
digitGroups[1] = (int)(25 % 1000) // second item of digitGroupsarray
'positive' gets divided again (25 / 1000) next time will be 0
and so on...
In these situation is very common and useful to log the values and debug the cycle. It really clears up your mind.
Working example:
static void Main(string[] args)
{
int groups = 3;
int[] digitGroups = new int[groups];
int positive = 25111;
for (int x = 0; x < groups; x++)
{
Console.WriteLine("positive value is: " + positive);
digitGroups[x] = (int)(positive % 1000);
positive /= 1000;
Console.WriteLine("item number (index): " + x + " value: " + digitGroups[x]);
}
}
Outputs:
positive value is: 25111
item number (index): 0 value: 111
positive value is: 25
item number (index): 1 value: 25
positive value is: 0
item number (index): 2 value: 0

Numbers to rounded off text

I am using the following function to convert numbers to text:
public static string NumberToText(long number)
{
StringBuilder wordNumber = new StringBuilder();
string[] powers = new string[] { "Thousand ", "Million ", "Billion " };
string[] tens = new string[] { "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety" };
string[] ones = new string[] { "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten",
"Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen" };
if (number == 0) { return "Zero"; }
if (number < 0)
{
wordNumber.Append("Negative ");
number = -number;
}
long[] groupedNumber = new long[] { 0, 0, 0, 0 };
int groupIndex = 0;
while (number > 0)
{
groupedNumber[groupIndex++] = number % 1000;
number /= 1000;
}
for (int i = 3; i >= 0; i--)
{
long group = groupedNumber[i];
if (group >= 100)
{
wordNumber.Append(ones[group / 100 - 1] + " Hundred ");
group %= 100;
if (group == 0 && i > 0)
wordNumber.Append(powers[i - 1]);
}
if (group >= 20)
{
if ((group % 10) != 0)
wordNumber.Append(tens[group / 10 - 2] + " " + ones[group % 10 - 1] + " ");
else
wordNumber.Append(tens[group / 10 - 2] + " ");
}
else if (group > 0)
wordNumber.Append(ones[group - 1] + " ");
if (group != 0 && i > 0)
wordNumber.Append(powers[i - 1]);
}
return wordNumber.ToString().Trim();
}
This works fine.
The issue is that the returned text is too long to read. I want to convert it to something shorter.
For eg: 345435234 is returned as three hundred and forty-five million, four hundred and thirty-five thousand, two hundred and thirty-four.
I instead would like 345.4 Mil.
Here are some more examples:
3454 should be 3.4K
34543 should be 34.5K
345433 should be 345.4K
... and so on.
How do I achieve this?
Maybe something like this?
Though if you have "printable character OCD" you could probably get it smaller
private static string[] suffixes = new[] { "", "K", "Mill", "Bill", "Trill", "Zill" };
public static string ToStuff(double number, int precision = 2)
{
const double unit = 1000;
var i = 0;
while (number > unit)
{
number /= unit;
i++;
}
if(i >= 5) throw new Exception("No one can count this high");
return Math.Round(number, precision, MidpointRounding.AwayFromZero) + suffixes[i];
}
Disclaimer : Totally untested
Update
Due to popular demand, i tested it with a test case of 1 E.g 2500000, 0 and it output 2Mill. I think i might have a career in this counting game
Update 2
Due to more popular demand, the consensus is that we shouldn't use .Net default rounding ToEven (bankers rounding) , and should use AwayFromZero
Try the following:
if (number>1000000)
string = floor(number/1000000).ToString() + "m";
else if (number > 1000)
string = floor(number/1000).ToString() + "k";
else
string = number.ToString();

IRC Bot - Roulette Command

I'm trying to make a roulette command for my bot, and this is what I got so far.
if (!String.IsNullOrEmpty(e.Data.Message.Replace("!roulette", ""))) {
string _u = e.Data.Nick;
string _b = e.Data.Message.Replace("!roulette", "");
string[] _c = { "R", "B", "G", "Red", "Black", "Green",
"r", "b", "g", "redblack green" };
Random _r = new Random();
int rnum = _r.Next(0, 36); // 0-35
if (_b.Contains(rnum.ToString()) && _b.Contains(_c.ToString())) {
MessageHandler(conf.Nick, e.Data.Nick + " spins the wheel.. " + _b.ToString() + " " + (string)_c[rnum] + "! We have a winner!", 8);
} else {
MessageHandler(conf.Nick, e.Data.Nick + " spins the wheel.. " + rnum.ToString() + " " + (string)_c[rnum] + "! You lose!", 8);
}
}
I get the Index outside the bounds of the array. error, it's very strange for something not so complicated.
How would I fix this, would I ignore the array and go for a Dictionary or List<>?
You are referencing _c array's element using the index rnum: _c[rnum].
Thernum variable can have any integer value from the range 0 - 35.
But the _c array has only 10 elements.
To fix it, limit the rnum variable to the range 0 - 9:
int rnum = _r.Next(0, 10);

Convert numbers in string to English word format

I have a C# method that converts integer numbers into their English word counterparts; however, how can I implement this so it'll work with a string.
For example, if I have the following string:
There was a dog. The dog ate 1000 bones. After eating, he was very sleepy. He slept for 12 hours.
I want it to parse it and return:
There was a dog. The dog ate one thousand bones. After eating, he was very sleepy. He slept for twelve hours.
How would I go by taking the numbers out of the sentence, and using the conversion method (below)?
public static string NumberToWords(int number)
{
if (number == 0)
return "zero";
if (number < 0)
return "minus " + NumberToWords(Math.Abs(number));
string words = "";
if ((number / 1000000) > 0)
{
words += NumberToWords(number / 1000000) + " million ";
number %= 1000000;
}
if ((number / 1000) > 0)
{
words += NumberToWords(number / 1000) + " thousand ";
number %= 1000;
}
if ((number / 100) > 0)
{
words += NumberToWords(number / 100) + " hundred ";
number %= 100;
}
if (number > 0)
{
if (words != "")
words += "and ";
var unitsMap = new[] { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
var tensMap = new[] { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
if (number < 20)
words += unitsMap[number];
else
{
words += tensMap[number / 10];
if ((number % 10) > 0)
words += "-" + unitsMap[number % 10];
}
}
return words;
}
I tried doing a foreach, like this, but it didn't work...
var matches = Regex.Matches(myString, "[0-9]+");
foreach(var match in matches)
{
NumberToWords(match);
}
You could use Split and LINQ:
var input = "There was a dog. The dog ate 1000 bones. After eating, he was very sleepy. He slept for 12 hours.";
var invalidChars = new [] { ',', ';', '-', '.' };
var words = input.Split(' ')
.Select(x =>
{
if (x.All(char.IsDigit) || x.Trim(invalidChars).All(char.IsDigit))
return NumberToWords(int.Parse(x.Trim(invalidChars)));
return x;
});
var output = string.Join(" ", words);
Btw I assume that NumberToWord method is working correctly.
You could use Selman22's approach, but in case you are not using a version of .NET with LINQ, you could use the RegularExpression replace function instead of Match.
http://msdn.microsoft.com/en-us/library/cft8645c(v=vs.110).aspx
You would just need a MatchEvaluator delegate like this:
static string matchEvaluator(Match m)
{
return NumberToWords(int.Parse(m.ToString()));
}
Much more simple way is to use Regex.Replace method utilizing MatchEvaluator.
string input = "There was a dog. The dog ate 1000 bones. After eating, he was very sleepy. He slept for 12 hours.";
string output = Regex.Replace(input, #"\d+", m => NumberToWords(int.Parse(m.Value)));
Minimal Changes to your existing code:
string s = "There was a dog. The dog ate 1000 bones. After eating, he was very sleepy. He slept for 12 hours.";
foreach (var match in Regex.Matches(s, "[0-9]+"))
{
string number = match.ToString();
s = s.Replace(number, NumberToWords(int.Parse(number)));
}
Console.WriteLine(s);

issues with Arrays in C#

Console.WriteLine("Please enter your number of the Names : ?");
int x = Convert.ToInt32(Console.ReadLine());
string[] names = new string[x];
for (int i = 0; i < x; i++)
{
Console.Write("Enter Name no.{0} : ", i + 1);
names[i] = Console.ReadLine();
}
Console.WriteLine("the items are {0}", names);
Console.ReadKey();
Now when I want to type down the names, it just prints the first Name entered!
Like if I have 5 names, in the last line in the
Console.WriteLine("the items are {0}", names);
it just prints out the 1st name!
You'll want to do a loop at the end as well
Either a for loop or a foreach, the current way you are using Console.WriteLine() is using the string.Format() overload
foreach (string name in names)
{
// Write out here
Console.WriteLine(name);
}
Join the strings together with the separator you want, before passing them to writeline.
Use string.Join to do so.
Passing an array to WriteLine makes out think you are passing an array with values to format.
You have to do a loop.
Console.Write("the items are");
for (int i = 0; i < names.Length; ++i)
{
Console.Write(" ");
Console.Write(names[i]);
}
Console.WriteLine();
//Console.WriteLine("the items are {0}.", String.Join(", ", names));
string argsFormat = ( 1 < x) ?
String.Join(", ", Enumerable.Range(0, x).Select(n => "{" + n + "}").ToArray())
.Replace(", {" + (x-1) + "}", " and {" + (x-1) + "}") + "."
:
argsFormat = "{0}.";
Console.WriteLine("the items are " + argsFormat , names);

Categories

Resources