Input into Characters - c#

Question is I have to make a console application where i input a number and it writes out symbol "|" as many i inserted. Example if i insert number 6 it writes out ||||||. And it keeps asking until I insert 0 and it closes. So far the input has been made like this :
int input;
Console.Write("\n\n Insert an number ---> ");
input = Convert.ToInt32(Console.ReadLine());
I have tried with char array but no use.

There is actually a constructor on string that initializes a string with the given character a certain number of times:
string s = new string('|', 10);
s will be the string "||||||||||"

Loops are so 2012 :)
using System;
using System.Linq;
internal class Program
{
private static void Main(string[] args)
{
Enumerable.Range(0, Int32.MaxValue)
.Select(i => Int32.TryParse(Console.ReadLine(), out i) ? i : -1)
.Where(i => i >= 0)
.TakeWhile(i => i > 0)
.Select(i => {
Console.WriteLine(String.Join("", Enumerable.Repeat("|", i)));
return 0;})
.Count();
}
}
Description (even the answer is very non-serious):
Enumerable.Range is to allow semi-infinite (as Chris Sinclair pointed out it is only 2,147,483,647 times) enumerable to have most of the code in single statement.
First Select reads input line by line and convert valid input to integers, the rest to -1 (note that in this sample -1 is possible value for "invalid input", normally one would return Tuple<int, bool> or int? to signify invalid values
Where filters out "invalid" inputs (correctly entered negative numbers as well all non-numbers that where reported as -1 by previous Select).
TakeWhile provides termination condition for 0.
Second Select prints result. Note that to construct string from multiple copies of the same character one should use proper new String("|", count) constructor, but it less fun.
finally Count forces immediate iteration of the query.

pseudo code
is read line a number
until read line is 0
for 1 to the number
print |
is read line a number
if not a number go back at asking the number saying it is not a number
if not a number go back at asking the number saying it is not a number
now have fun doing your homework

tow basic concepts you should know
the for loop:
for(int i=0; i<input; i++)
{
// do stuff
}
This is a common patter for doing something input times, so if input is equal to 6, than it will //do stuff 6 times.
Console.Write
Console.Write('|');
Console.Write writes the text to the console without adding adding a new line at the end.
I'm sure that you can combine some of these language features somehow, to fulfill your requirement.

Related

What is stopping this program from having an output

I made this code to brute force anagrams by printing all possible permutables of the characters in a string, however there is no output. I do not need simplifications as I am a student still learning the basics, I just need help getting it to work this way so I can better understand it.
using System;
using System.Collections.Generic;
namespace anagramSolver
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter anagram:");
string anagram = Console.ReadLine();
string temp = "";
List<string> storeStr = new List<string>(0);
List<int> storeInt = new List<int>(0);
//creates factorial number for anagram
int factorial = 1;
for (int i = anagram.Length; i > 0; i--)
{
factorial *= i;
}
while (storeStr.Count != factorial)
{
Random rnd = new Random();
while(temp.Length != anagram.Length)
{
int num = rnd.Next(anagram.Length - 1);
if (storeInt.Contains(num) == true)
{
}
else
{
storeInt.Add(num);
temp += anagram[num];
}
}
if (storeStr.Contains(temp) == true)
{
temp = "";
}
else
{
storeStr.Add(temp);
Console.WriteLine(temp, storeStr.Count);
temp = "";
}
}
}
}
}
edit: added temp reset after it is deemed contained by storeStr
Two main issues causing infinite loop:
1)
As per Random.Next documentation, the parameter is the "exclusive" upper bound. This means, if you want a random number between 0 and anagram.Length - 1 included, you should use rnd.Next(anagram.Length);.
With rnd.Next(anagram.Length - 1), you'll never hit anagram.Length - 1.
2)
Even if you solve 1, only the first main iteration goes well.
storeInt is never reset. Meaning, after the first main iteration, it will have already all the numbers in it.
So, during the second iteration, you will always hit the case if (storeInt.Contains(num) == true), which does nothing and the inner loop will go on forever.
Several issues here...
The expression rnd.Next(anagram.Length - 1) generates a value between 0 and anagram.Length - 2. For an input with two characters it will always return 0, so you'll never actually generate a full string. Remove the - 1 from it and you'll be fine.
Next, you're using a list to keep track of the character indices you've used already, but you never clear the list. You'll get one output (eventually, when the random number generator covers all the values) and then enter an infinite loop on the next generation pass. Clear storeInt after the generation loop to fix this.
While not a true infinite loop, creating a new instance of the random number generator each time will give you a lot of duplication. new Random() uses the current time as a seed value and you could potentially get through a ton of loops with each seed, generating exactly the same values until the time changes enough to change your random sequence. Create the random number generator once before you start your main loop.
And finally, your code doesn't handle repeated input letters. If the input is "aa" then there is only a single distinct output, but your code won't stop until it gets two. If the input was "aab" there are three distinct permutations ("aab", "aba", "baa") which is half of the expected results. You'll never reach your exit condition in this case. You could do it by keeping track of the indices you've used instead of the generated strings, it just makes it a bit more complex.
There are a few ways to generate permutations that are less error-prone. In general you should try to avoid "keep generating random garbage until I find the result I'm looking for" solutions. Think about how you personally would go about writing down the full list of permutations for 3, 4 or 5 inputs. What steps would you take? Think about how that would work in a computer program.
this loop
while(temp.Length != anagram.Length)
{
int num = rnd.Next(anagram.Length - 1);
if (storeInt.Contains(num) == true)
{
}
else
{
storeInt.Add(num);
temp += anagram[num];
}
}
gets stuck.
once the number is in storeInt you never change storeStr, yet thats what you are testing for loop exit

C# string.split on readline not producing expected array length

Hi guys just carrying on working on my first app, done mainly to learn and nothing else. I want the user to be able to type in 2d6+4 OR 2d6, you should be able to substitute those numbers for any number. I'm getting errors parsing the information and I think it has something to do with the array containing more or less values than I anticipated, or it for some reason left the delimiter in. typing 2d6+4 or 2d6 +4 works fine, 2d6 however does not, which is what I thought the if statement should guard against. Any ideas?
Console.WriteLine("Please type the roll you would like to perform, for example - 2d6+4");
var rollLine = Console.ReadLine();
var diceLine = rollLine.Split(new Char[] { 'd', '+' }, StringSplitOptions.RemoveEmptyEntries);
diceCount = int.Parse(diceLine[0]);
diceType = int.Parse(diceLine[1]);
if (rollLine.Length > 2)
{
bonus = int.Parse(diceLine[2]);
}
else
{
bonus = 0;
}
It looks like you are just using the wrong variable for the length comparison. You are comparing the length of the string, not the length of the split array. It should be:
if (diceLine.Length > 2)
When user entered "2d6", the string length is 3, i.e. following rule is true
if (rollLine.Length > 2)
However, as per your logic you will get array of 2 items in the diceLine, i.e. diceLine[0] and diceLine[1] but after condition with length you call diceLine[2] that does not exist.
I.e. either change condition to
if (rollLine.Length == 5) // 2d6+4
or check for the length of the array
if (diceLine.Length > 2)
You want your IF to check if the rollLine length is greater than 3, not 2.
As the smallest thing you'll type in is, for example, 2d6, you want to check for the bonus only when the rollLine is more than 3 characters.
if (rollLine.Length > 3)
{
bonus = int.Parse(diceLine[2]);
}

How can I rewrite values from an array into a second array with each 2 letters being flipped? (C#)

This is for a homework assignment which I have been working on for quite a while now but have not been able to figure out. Here are the exact instructions from my teacher if you need them; it is at number five that I am stuck:
(1) Have the user enter a sentence that they want to have encoded.
(2) If the number of characters in the message is odd, concatenate a space (" ") to their message so that our message will always be an even number of letters.
(3) Now create a new char[], call it unCoded where each element is a letter from your secret message.
(4) Now create an empty second char[], call it coded, and define its length equal to the length of the other char[], unCoded.
(5) Now write the values from the uncoded array into the coded array, but flipping each 2 letters.
(6) Then write out the original uncoded message.
(7) Then write out the new coded message.
He also said step 5 must be done in a loop.
Any help would be appreciated, thanks.
What I have so far:
static void Main(string[] args)
{
Console.WriteLine("Enter the sentence you want encoded: ");
string userInput = Console.ReadLine();
int remainder = userInput.Length % 2;
if (remainder!=0)
{
userInput = userInput + " ";
}
char[] unCoded = userInput.ToArray();
char[] coded=unCoded;
//coded.Length = unCoded.Length;
for (int i = 0; i < unCoded.Length; i=i+2)
{
coded[0] = unCoded[1];
coded[1] = unCoded[0];
}
string encoded = new string(coded);
Console.WriteLine("{0}", userInput);
Console.WriteLine("{0}", encoded);
Console.ReadKey();
}
Well, in your loop you don't use the loop parameter, so you just change up the first two values several times. Consider what you are doing in your loop to be the first step of what you actually want to achieve. Do it using the "i" variable and knowing that it's first value is 0. Then when i "grows", the loop will do the same for the next two values.
so just put i in place of 0 and i+1 in place of 1

Shuffle an array without creating any runs

I have an array of repeating letters:
AABCCD
and I would like to put them into pseudo-random order. Simple right, just use Fisher-Yates => done. However there is a restriction on the output - I don't want any runs of the same letter. I want at least two other characters to appear before the same character reappears. For example:
ACCABD
is not valid because there are two Cs next to each other.
ABCACD
is also not valid because there are two C's next to each other (CAC) with only one other character (A) between them, I require at least two other characters.
Every valid sequence for this simple example:
ABCADC ABCDAC ACBACD ACBADC ACBDAC ACBDCA ACDABC ACDACB ACDBAC ACDBCA
ADCABC ADCBAC BACDAC BCADCA CABCAD CABCDA CABDAC CABDCA CADBAC CADBCA
CADCAB CADCBA CBACDA CBADCA CDABCA CDACBA DACBAC DCABCA
I used a brute force approach for this small array but my actual problem is arrays with hundreds of elements. I've tried using Fisher-Yates with some suppression - do normal Fisher-Yates and then if you don't like the character that comes up, try X more times for a better one. Generates valid sequences about 87% of the time only and is very slow. Wondering if there's a better approach. Obviously this isn't possible for all arrays. An array of just "AAB" has no valid order, so I'd like to fail down to the best available order of "ABA" for something like this.
Here is a modified Fisher-Yates approach. As I mentioned, it is very difficult to generate a valid sequence 100% of the time, because you have to check that you haven't trapped yourself by leaving only AAA at the end of your sequence.
It is possible to create a recursive CanBeSorted method, which tells you whether or not a sequence can be sorted according to your rules. That will be your basis for a full solution, but this function, which returns a boolean value indicating success or failure, should be a starting point.
public static bool Shuffle(char[] array)
{
var random = new Random();
var groups = array.ToDictionary(e => e, e => array.Count(v => v == e));
char last = '\0';
char lastButOne = '\0';
for (int i = array.Length; i > 1; i--)
{
var candidates = groups.Keys.Where(c => groups[c] > 0)
.Except(new[] { last, lastButOne }).ToList();
if (!candidates.Any())
return false;
var #char = candidates[random.Next(candidates.Count)];
var j = Array.IndexOf(array.Take(i).ToArray(), #char);
// Swap.
var tmp = array[j];
array[j] = array[i - 1];
array[i - 1] = tmp;
lastButOne = last;
last = #char;
groups[#char] = groups[#char] - 1;
}
return true;
}
Maintain a link list that will keep track of the letter and it's position in the result.
After getting the random number,Pick it's corresponding character from the input(same as Fisher-Yates) but now search in the list whether it has already occurred or not.
If not, insert the letter in the result and also in the link list with its position in the result.
If yes, then check it's position in the result(that you have stored in the link list when you have written that letter in result). Now compare this location with the current inserting location, If mod(currentlocation-previouslocation) is 3 or greater, you can insert that letter in the result otherwise not, if not choose the random number again.

Comparing 2 huge lists using C# multiple times (with a twist)

Hey everyone, great community you got here. I'm an Electrical Engineer doing some "programming" work on the side to help pay for bills. I say this because I want you to take into consideration that I don't have proper Computer Science training, but I have been coding for the past 7 years.
I have several excel tables with information (all numeric), basically it is "dialed phone numbers" in one column and number of minutes to each of those numbers on another. Separately I have a list of "carrier prefix code numbers" for the different carriers in my country. What I want to do is separate all the "traffic" per carrier. Here is the scenario:
First dialed number row: 123456789ABCD,100 <-- That would be a 13 digit phone number and 100 minutes.
I have a list of 12,000+ prefix codes for carrier 1, these codes vary in length, and I need to check everyone of them:
Prefix Code 1: 1234567 <-- this code is 7 digits long.
I need to check the first 7 digits for the dialed number an compare it to the dialed number, if a match is found, I would add the number of minutes to a subtotal for later use. Please consider that not all prefix codes are the same length, some times they are shorter or longer.
Most of this should be a piece of cake, and I could should be able to do it, but I'm getting kind of scared with the massive amount of data; Some times the dialed number lists consists of up to 30,000 numbers, and the "carrier prefix code" lists around 13,000 rows long, and I usually check 3 carriers, that means I have to do a lot of "matches".
Does anyone have an idea of how to do this efficiently using C#? Or any other language to be kind honest. I need to do this quite often and designing a tool to do it would make much more sense. I need a good perspective from someone that does have that "Computer Scientist" background.
Lists don't need to be in excel worksheets, I can export to csv file and work from there, I don't need an "MS Office" interface.
Thanks for your help.
Update:
Thank you all for your time on answering my question. I guess in my ignorance I over exaggerated the word "efficient". I don't perform this task every few seconds. It's something I have to do once per day and I hate to do with with Excel and VLOOKUPs, etc.
I've learned about new concepts from you guys and I hope I can build a solution(s) using your ideas.
UPDATE
You can do a simple trick - group the prefixes by their first digits into a dictionary and match the numbers only against the correct subset. I tested it with the following two LINQ statements assuming every prefix has at least three digis.
const Int32 minimumPrefixLength = 3;
var groupedPefixes = prefixes
.GroupBy(p => p.Substring(0, minimumPrefixLength))
.ToDictionary(g => g.Key, g => g);
var numberPrefixes = numbers
.Select(n => groupedPefixes[n.Substring(0, minimumPrefixLength)]
.First(n.StartsWith))
.ToList();
So how fast is this? 15.000 prefixes and 50.000 numbers took less than 250 milliseconds. Fast enough for two lines of code?
Note that the performance heavily depends on the minimum prefix length (MPL), hence on the number of prefix groups you can construct.
MPL Runtime
-----------------
1 10.198 ms
2 1.179 ms
3 205 ms
4 130 ms
5 107 ms
Just to give an rough idea - I did just one run and have a lot of other stuff going on.
Original answer
I wouldn't care much about performance - an average desktop pc can quiete easily deal with database tables with 100 million rows. Maybe it takes five minutes but I assume you don't want to perform the task every other second.
I just made a test. I generated a list with 15.000 unique prefixes with 5 to 10 digits. From this prefixes I generated 50.000 numbers with a prefix and additional 5 to 10 digits.
List<String> prefixes = GeneratePrefixes();
List<String> numbers = GenerateNumbers(prefixes);
Then I used the following LINQ to Object query to find the prefix of each number.
var numberPrefixes = numbers.Select(n => prefixes.First(n.StartsWith)).ToList();
Well, it took about a minute on my Core 2 Duo laptop with 2.0 GHz. So if one minute processing time is acceptable, maybe two or three if you include aggregation, I would not try to optimize anything. Of course, it would be realy nice if the programm could do the task in a second or two, but this will add quite a bit of complexity and many things to get wrong. And it takes time to design, write, and test. The LINQ statement took my only seconds.
Test application
Note that generating many prefixes is really slow and might take a minute or two.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace Test
{
static class Program
{
static void Main()
{
// Set number of prefixes and calls to not more than 50 to get results
// printed to the console.
Console.Write("Generating prefixes");
List<String> prefixes = Program.GeneratePrefixes(5, 10, 15);
Console.WriteLine();
Console.Write("Generating calls");
List<Call> calls = Program.GenerateCalls(prefixes, 5, 10, 50);
Console.WriteLine();
Console.WriteLine("Processing started.");
Stopwatch stopwatch = new Stopwatch();
const Int32 minimumPrefixLength = 5;
stopwatch.Start();
var groupedPefixes = prefixes
.GroupBy(p => p.Substring(0, minimumPrefixLength))
.ToDictionary(g => g.Key, g => g);
var result = calls
.GroupBy(c => groupedPefixes[c.Number.Substring(0, minimumPrefixLength)]
.First(c.Number.StartsWith))
.Select(g => new Call(g.Key, g.Sum(i => i.Duration)))
.ToList();
stopwatch.Stop();
Console.WriteLine("Processing finished.");
Console.WriteLine(stopwatch.Elapsed);
if ((prefixes.Count <= 50) && (calls.Count <= 50))
{
Console.WriteLine("Prefixes");
foreach (String prefix in prefixes.OrderBy(p => p))
{
Console.WriteLine(String.Format(" prefix={0}", prefix));
}
Console.WriteLine("Calls");
foreach (Call call in calls.OrderBy(c => c.Number).ThenBy(c => c.Duration))
{
Console.WriteLine(String.Format(" number={0} duration={1}", call.Number, call.Duration));
}
Console.WriteLine("Result");
foreach (Call call in result.OrderBy(c => c.Number))
{
Console.WriteLine(String.Format(" prefix={0} accumulated duration={1}", call.Number, call.Duration));
}
}
Console.ReadLine();
}
private static List<String> GeneratePrefixes(Int32 minimumLength, Int32 maximumLength, Int32 count)
{
Random random = new Random();
List<String> prefixes = new List<String>(count);
StringBuilder stringBuilder = new StringBuilder(maximumLength);
while (prefixes.Count < count)
{
stringBuilder.Length = 0;
for (int i = 0; i < random.Next(minimumLength, maximumLength + 1); i++)
{
stringBuilder.Append(random.Next(10));
}
String prefix = stringBuilder.ToString();
if (prefixes.Count % 1000 == 0)
{
Console.Write(".");
}
if (prefixes.All(p => !p.StartsWith(prefix) && !prefix.StartsWith(p)))
{
prefixes.Add(stringBuilder.ToString());
}
}
return prefixes;
}
private static List<Call> GenerateCalls(List<String> prefixes, Int32 minimumLength, Int32 maximumLength, Int32 count)
{
Random random = new Random();
List<Call> calls = new List<Call>(count);
StringBuilder stringBuilder = new StringBuilder();
while (calls.Count < count)
{
stringBuilder.Length = 0;
stringBuilder.Append(prefixes[random.Next(prefixes.Count)]);
for (int i = 0; i < random.Next(minimumLength, maximumLength + 1); i++)
{
stringBuilder.Append(random.Next(10));
}
if (calls.Count % 1000 == 0)
{
Console.Write(".");
}
calls.Add(new Call(stringBuilder.ToString(), random.Next(1000)));
}
return calls;
}
private class Call
{
public Call (String number, Decimal duration)
{
this.Number = number;
this.Duration = duration;
}
public String Number { get; private set; }
public Decimal Duration { get; private set; }
}
}
}
It sounds to me like you need to build a trie from the carrier prefixes. You'll end up with a single trie, where the terminating nodes tell you the carrier for that prefix.
Then create a dictionary from carrier to an int or long (the total).
Then for each dialed number row, just work your way down the trie until you find the carrier. Find the total number of minutes so far for the carrier, and add the current row - then move on.
The easiest data structure that would do this fairly efficiently would be a list of sets. Make a Set for each carrier to contain all the prefixes.
Now, to associate a call with a carrier:
foreach (Carrier carrier in carriers)
{
bool found = false;
for (int length = 1; length <= 7; length++)
{
int prefix = ExtractDigits(callNumber, length);
if (carrier.Prefixes.Contains(prefix))
{
carrier.Calls.Add(callNumber);
found = true;
break;
}
}
if (found)
break;
}
If you have 10 carriers, there will be 70 lookups in the set per call. But a lookup in a set isn't too slow (much faster than a linear search). So this should give you quite a big speed up over a brute force linear search.
You can go a step further and group the prefixes for each carrier according to the length. That way, if a carrier has only prefixes of length 7 and 4, you'd know to only bother to extract and look up those lengths, each time looking in the set of prefixes of that length.
How about dumping your data into a couple of database tables and then query them using SQL? Easy!
CREATE TABLE dbo.dialled_numbers ( number VARCHAR(100), minutes INT )
CREATE TABLE dbo.prefixes ( prefix VARCHAR(100) )
-- now populate the tables, create indexes etc
-- and then just run your query...
SELECT p.prefix,
SUM(n.minutes) AS total_minutes
FROM dbo.dialled_numbers AS n
INNER JOIN dbo.prefixes AS p
ON n.number LIKE p.prefix + '%'
GROUP BY p.prefix
(This was written for SQL Server, but should be very simple to translate for any other DBMS.)
Maybe it would be simpler (not necessarily more efficient) to do it in a database instead of C#.
You could insert the rows on the database and on insert determine the carrier and include it in the record (maybe in an insert trigger).
Then your report would be a sum query on the table.
I would probably just put the entries in a List, sort it, then use a binary search to look for matches. Tailor the binary search match criteria to return the first item that matches then iterate along the list until you find one that doesn't match. A binary search takes only around 15 comparisons to search a list of 30,000 items.
You may want to use a HashTable in C#.
This way you have key-value pairs, and your keys could be the phone numbers, and your value the total minutes. If a match is found in the key set, then modify the total minutes, else, add a new key.
You would then just need to modify your searching algorithm, to not look at the entire key, but only the first 7 digits of it.

Categories

Resources