I'm a newer programmer with C#. I am having an issue where my character frequency reading program is not displaying the ASCII values correctly. What it is supposed to do is read from a text file, convert all uppercase to lowercase, display the ASCII values, frequency appeared, and percentage of the total number of characters each character appears in the file and then sort the list by frequency. Below is my code so far:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.IO;
using LibUtil;
using LibDate;
namespace Ch8Prb3
{
class Program
{
const string INPUT_FILE_NAME = "\\CIS210\\Ch8Prb3\\TextDat.Txt";
const string OUTPUT_FILE_NAME = "\\CIS210\\Ch8Prb3\\Ch8Prb3Rpt.Txt";
int count;
static StreamReader fileIn;
static StreamWriter fileOut;
static void Main()
{
ConsoleApp.ClrScr(); IdentifyApplication();
OpenFiles(); LetterFreq();
CloseFiles();
}
static void IdentifyApplication()
{
Console.WriteLine();
Console.WriteLine("Application: Ch8Prb3 -- Find and display a character-frequency ");
Console.WriteLine(" report of only letter chracters and their");
Console.WriteLine(" ASCII values from a text file.");
Console.WriteLine();
}
static void OpenFiles()
{
try
{
fileIn = File.OpenText(INPUT_FILE_NAME);
Console.WriteLine("{0} was opened", INPUT_FILE_NAME);
}
catch
{
Console.WriteLine("Error: {0} does not exist\n", INPUT_FILE_NAME);
ConsoleApp.Exit();
}
try
{
fileOut = File.CreateText(OUTPUT_FILE_NAME);
Console.WriteLine("{0} was created\n", OUTPUT_FILE_NAME);
}
catch
{
Console.WriteLine("Error: {0} could not be created\n", OUTPUT_FILE_NAME);
ConsoleApp.Exit();
}
}
static void LetterFreq()
{
int[] c = new int[(int)char.MaxValue];
int total = 0;
int j = 0;
string s = File.ReadAllText("\\CIS210\\Ch8Prb3\\TextDat.Txt");
string l = Convert.ToString(Encoding.ASCII.GetBytes(s));
s = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToLower(s.ToLower());
double percent;
foreach (char t in s)
{
c[(int)t]++;
}
PrintHeader();
for (int i = 0; i < (int)char.MaxValue; i++)
{
if (c[i] > 0 && char.IsLetter((char)i))
{
total += c[i];
percent = c[i] / total * 100;
fileOut.WriteLine(" {0} {1,3} {2,3} {3,2:f2}", (char)i, l, c[i], percent);
}
}
fileOut.WriteLine();
fileOut.WriteLine("Number of Characters: {0}", total);
}
static void PrintHeader()
{
fileOut.WriteLine(" Chapter 8 Problem 3");
fileOut.WriteLine("Character Frequency Report");
fileOut.WriteLine(" {0:MM/dd/yyyy}", Date.Today);
fileOut.WriteLine();
fileOut.WriteLine(" ASCII ");
fileOut.WriteLine("Char Value Freq Percent");
fileOut.WriteLine("---- ----- ---- -------");
}
static void CloseFiles()
{
fileIn.Close(); fileOut.Close();
}
}
}
Instead of getting the ASCII value of each character, I'm getting System.Byte [] all the way down the ASCII column.
Help!
This is the problem:
Convert.ToString(Encoding.ASCII.GetBytes(s));
Encoding.GetBytes(string) returns a byte[], and calling Convert.ToString() on that will just return System.Byte[].
It's not clear why you're using Encoding.ASCII at all here - you've got the contents of the file as a string, on the previous line:
string s = File.ReadAllText("\\CIS210\\Ch8Prb3\\TextDat.Txt");
Just use that instead of l. It's not clear what you're expecting to do with l anyway, to be honest. By "ASCII value" if you mean the Unicode code point for the character, just cast i to int:
fileOut.WriteLine(" {0} {1,3} {2,3} {3,2:f2}", (char)i, (int) i, c[i], percent);
Oh, and you probably want to change the way you're computing percent, too - you're using integer arithmetic, so the result will always be 0.
It's not clear why you're lower-casing the string twice either, by the way. Don't you think once is enough? Why are you lower-casing at all?
Oh, and you open an input file, but never do anything with it. Why?
There are various other things I'd change about your code - not least the layout (one statement per line, almost always!) - but this'll do for a start.
You program con be condensed considerably using list and groupby:
class Program
{
const string INPUT_FILE_NAME = "\\CIS210\\Ch8Prb3\\TextDat.Txt";
static void Main(string[] args)
{
var s = System.IO.File.ReadAllText(INPUT_FILE_NAME).ToLower();
var list = s.ToList();
var group = list.GroupBy(i => i);
foreach (var g in group)
{
Console.WriteLine("{0} {1}", g.Key, g.Count());
}
Console.ReadLine();
}
}
Related
when I enter 1 for n
and 1111 for lines
the sum must be 1+1+1+1=4 but the output is 1.
THIS IS THE QUESTION...
you will get a (n) then (n) lines as an input, In each line there are some numbers (we don’t know how many they are) and you must print (n) lines, In the i-th line print the sum of numbers in the i-th line.
using System;
namespace prom2
{
class Program
{
static void Main(string[] args)
{
int lines=0, sum = 0;
Console.Write("Enter a number of lines ");
int n = int.Parse(Console.ReadLine());
for (int i = 1; i <= n&n>0&1000>n; i++)
{
Console.WriteLine("Enter line " + i + " numbers");
lines = int.Parse(Console.ReadLine());
lines = lines / 10;
sum += lines % 10;
Console.WriteLine("sum is " + sum);
}
}
}
}
Try this:
static void Main(string[] args)
{
int input;
bool times = true;
List<int> numbers = new List<int>();
while (times)
{
Console.Clear();
Console.WriteLine("Enter number: ");
var num = int.TryParse(Console.ReadLine(), out input);//tryparse will output a bool into num and set input to a int
if (num)
{
numbers.Add(input);//only integers will be added to list
}
Console.Clear();
Console.WriteLine("Another? Y or N");//ask if they want to sum more numbers
var yesno = Console.ReadLine();//get answer from user
if (yesno.ToUpper().Trim() != "Y")//if N or anything else
{
//assume no
times = false;
}
Console.Clear();
}
var sum = numbers.Sum();
Console.WriteLine("Sum : " + sum.ToString());
Console.ReadLine();//just to pause screen
}
Because Console.ReadLine returns a string, and it's possible to treat a string as if it's an array of chars (where char represents a single character), you can have a method like this to calculate the sum of all the digits in a single line:
private int SumTheDigits(string line)
{
var sum = 0;
foreach (var character in line)
{
sum += int.Parse(character.ToString());
}
return sum;
}
Please note this method contains no validation - ideally you should validate that line is purely numeric, otherwise int.Parse will throw an exception, although the same is true of the code you provided too.
If you want to work with multiple lines of console input, just call this method from within another loop which solicits / works through those lines of console input.
Edit
My answer doesn't answer all of your question, it only answers the part which asks how to calculate the sum of the digits in a numeric string, and it does work, to the extent that it correctly does what it says on the tin.
Here's all the code I wrote to validate the answer before posting the original answer (I wrote it as a xUnit unit test rather than a console application, but that doesn't change the fact that the code I shared works):
using System;
using Xunit;
namespace StackOverflow71442136SumDigits
{
public class UnitTest1
{
[Theory]
[InlineData("1", 1)]
[InlineData("12", 3)]
[InlineData("23", 5)]
[InlineData("1234", 10)]
[InlineData("123456789", 45)]
public void Test1(string line, int expectedSum)
{
var actualSum = this.SumTheDigits(line);
Assert.Equal(expectedSum, actualSum);
}
private int SumTheDigits(string line)
{
var sum = 0;
foreach (var character in line)
{
sum += int.Parse(character.ToString());
}
return sum;
}
}
}
You might want to read How do I ask and answer homework questions?
I'm making a Caesar cipher, currently I have a shift of three that I want to encrypt the message with. If any letter has "x, y or z" it will give me an out of bounds array error (because the shift is 3).
How can I pass the error by going back to the start of the array, but ending with the remainder of the shift?
This is my code currently:
using System;
using System.Text;
//caesar cipher
namespace Easy47
{
class Program
{
static void Main(string[] args)
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var input = Input(alphabet);
Encrypt(3, input, alphabet);
Console.WriteLine();
}
private static void Encrypt(int shift, string input, string alphabet)
{
var message = new StringBuilder();
foreach (char letter in input)
{
for (int i = 0; i < alphabet.Length; i++)
{
if (letter == alphabet[i])
{
message.Append(alphabet[i + shift]);
}
}
}
Console.WriteLine("\n" + message);
}
private static string Input(string alphabet)
{
Console.Write("Input your string\n\n> ");
string input = Console.ReadLine().ToUpper();
return input;
}
}
}
You use the modulo operator:
var i = 255
var z = i % 200 // z == 55
in your case here:
for (int i = 0; i < alphabet.Length; i++)
{
if (letter == alphabet[i])
{
message.Append(alphabet[ (i + shift) % alphabet.Length]);
}
}
If after your addition of shift the index is bigger then alphabet.Length it will start at 0 again.
See C# Ref Modulo Operator
Unrelated, but your loop is not very efficient. A message of "ZZZZZ" would go 5 times through your full alphabet to get translated. You should use a Dictionary as lookup. You can create it at the start before you translate the message and then your lookup is very fast - thats what dictionarys excel at. O(1) lookups :o)
If you know a little about linq, this should be understandable:
// needs: using System.Linq;
private static void Encrypt(int shift, string input, string alphabet)
{
var message = new StringBuilder();
// create a string that is shifted by shift characters
// skip: skips n characters, take: takes n characters
// string.Join reassables the string from the enumerable of chars
var moved = string.Join("",alphabet.Skip(shift))+string.Join("",alphabet.Take(shift));
// the select iterates through your alphabet, c is the character you currently handle,
// i is the index it is at inside of alphabet
// the rest is a fancy way of creating a dictionary for
// a->d
// b->e
// etc using alphabet and the shifted lookup-string we created above.
var lookup = alphabet
.Select( (c,i)=> new {Orig=c,Chiff=moved[i]})
.ToDictionary(k => k.Orig, v => v.Chiff);
foreach (char letter in input)
{
// if the letter is not inside your alphabet, you might want to add
// it "as-is" in a else-branch. (Numbers or dates or .-,?! f.e.)
if (lookup.ContainsKey(letter))
{
message.Append(lookup[letter]);
}
}
Console.WriteLine("\n" + message);
}
Here's a description of what I need to do:
Write a program that first initializes arrays via user input with the names and wages of all employees, then prompts the user for the hours worked for each employee and computes their regular pay, overtime pay, gross income, federal tax deduction (10% of gross), state tax deduction (5% of gross), and net income. After the last employee is processed, the program displays totals for regular pay and overtime pay and the names and gross incomes for the employees that earned the most and least amount.
I'm stuck at the if-else statement, I'm fairly new to c# and still don't know a lot, basically I'm stuck, and I'm in a rush to get this done, I would appreciate any help on this.
using System;
using static System.Console;
namespace Exercise3
{
class ArrayCalculations
{
static void Main(string[] args)
{
double hours,
regularPay,
overtimePay,
grossPay,
netPay,
stateTax,
fedTax;
const double FED_TAX = .10;
const double STATE_TAX = .05;
const double REG_HOURS = 40.0;
const double OVERTIME = 1.5;
string[] name = new string[5];
double[] wage = new double[5];
for (int i = 0; i < name.Length; i++)
{
Write("Please enter name: ", (i + 1));
name[i] = ReadLine();
Write("Please enter your hourly wage: ", (i + 1));
wage[i] = Convert.ToDouble(ReadLine());
Write("Please enter hours worked this week", (i + 1));
hours = Convert.ToDouble(ReadLine());
}
WriteLine();
for (int i = 0; i < name.Length; i++)
{
WriteLine("Name: " + name[i] + " Wage: " + wage[i]);
}
if (hours <= 40)
{
regularPay = hours * wage;
overtimePay = 0;
}
else
{
// ??
}
}
}
}
1.) Try to split your code into logic pieces:
private double CalculateWage(double hours, double wage)
{
return (hours * wage);
}
Or like this:
private string GetUserInput_String(string message, int index)
{
Write(message, index);
return ReadLine();
}
Now you can call it like this:
name[i] = GetUserInput_String("Please enter name: ", (i + 1))
Same for doubles.
private string GetUserInput_Double(string message, int index)
{
try
{
Write("Please enter wage: ", (i + 1));
return Convert.ToDouble(ReadLine());
//OR
double result;
double.TryParse(ReadLine(),out result);
if(result != 0)
{
return result;
}
return null;
}
catch(Exception ex) //Catch all thrown Exception
{
Write(ex.Message);//Handle Exceptions (log, retry,..)
return null; //When retunring null check for null when working with the returned value !!!
}
}
2.) Use Try {} catch {}
Catch and handle exception ALWAYS when casting, converting, etc.
Check out Linq:
private void PrintWages(string[] names, double[] wages)
{
names.ToList().ForEach(x => Console.WriteLine($"Name: {x} Wage: {wages[names.ToList().IndexOf(x)]}"));
}
This does the following:
string[] names = {"Anna", "Peter", "Marc"};
string[] wages = { "1500", "2000", "3500" };
names.ToList().ForEach(x => Console.WriteLine($"Name: {x} Wage: {wages[names.ToList().IndexOf(x)]}"));
Output:
Name: Anna Wage: 1500
Name: Peter Wage: 2000
Name: Marc Wage: 3500
So what have I done here:
using System.Linq; - Adds the "Foreach" and other extension methods to Collections
array.ToList() => array converted to list
Foreach element in names I called WriteLine();
names.ToList().IndexOf(x) gives me the index of the current element to use in wages[index]
I condesed the output via Interplated Strings
So the more or less complete result would be sth. like this
//Care of naming !
// string[] names - its a sort of collection of names so dont call it name.
// name would be ONE item of that array
//I recommend using List<sting> / List<double> here !
List<string> employees = new List<string>();
List<double> wages = new List<double>();
//Or way better => Dictionairy<string, double>(),
//A Dictionairy has a Key (unique) and a correlating value
Dictionary<string, double> EmployeeWages = new Dictionary<string, double>();
int employeesToAdd = 0;
try
{
Console.Write("How many employees would you like to add ?");
employeesToAdd = int.Parse(Console.ReadLine());
}
catch (Exception ex)
{
Console.Write($"Error: {ex.Message}");
return;
}
//We reach this line only if employeesToAdd has a value !
for (int i = 0; i < employeesToAdd; i++)
{
EmployeeWages.Add(GetUserInput_String("Please enter name: "), GetUserInput_Double("Please enter your wage: "));
}
PrintResult(EmployeeWages);
I can't figure out how to pass total, sale and comm into Main().
Anybody got an idea how to get those variables into Main and display (output) them there with the names?
Right now I can just output the variables in calcComm ...
Thanks in advance
Philip
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication38
{
class Program
{
public static void getsales()
{
string inputsales;
double total = 0;
double sale = 0;
for (int salecount = 1; salecount <= 3; ++salecount)
{
Console.WriteLine("Enter sale: ");
inputsales = Console.ReadLine();
sale = Convert.ToDouble(inputsales);
total = total + sale;
}
calcComm(total);
}
public static void calcComm(double total)
{
double comm = 0;
comm = total * 0.2;
Console.WriteLine(comm);
}
public static void Main ()
{
Console.WriteLine(" Sunshine Hot Tubs \n Sales Commissions Report\n");
char Letter;
const string name1 = "Andreas";
const string name2 = "Brittany";
const string name3 = "Eric";
string inputLetter;
string name;
Console.WriteLine("Please enter intial or type 'z' to quit");
inputLetter = Console.ReadLine();
Letter = Convert.ToChar(inputLetter);
while (Letter != 'z')
{
if (Letter == 'a')
{
name = name1;
getsales();
}
else if (Letter == 'b')
{
name = name2;
getsales();
}
else if (Letter == 'e')
{
name = name3;
getsales();
}
else
{
Console.WriteLine("Invalid entry try again");
}
Console.WriteLine("Please enter intial or type z to quit");
inputLetter = Console.ReadLine();
Letter = Convert.ToChar(inputLetter);
}
}
}
}
This gives an array of strings corresponding to the command line parameters.
Main(string [] args)
By the way, when dealing with monetary units, it's better to use decimal than double.
You should be using objects, then you can make those public.
class Sales
{
public double total;
public double sale;
public double comm;
...
public void CalcComm()
{
...
}
}
Then you can reference them like this:
Sales.total, Sales.sale
Or you can make them global but that's not normally advisable.
Look into the return keyword in C#; get your functions to return the relevant data back to main and have it make use of it.
Consider this example for how to add command line arguments. If you need them to be programmatically added consider writing a wrapper program and starting the Process inside it.
using System;
class Program
{
static void Main(string[] args)
{
if (args == null)
{
Console.WriteLine("args is null"); // Check for null array
}
else
{
Console.Write("args length is ");
Console.WriteLine(args.Length); // Write array length
for (int i = 0; i < args.Length; i++) // Loop through array
{
string argument = args[i];
Console.Write("args index ");
Console.Write(i); // Write index
Console.Write(" is [");
Console.Write(argument); // Write string
Console.WriteLine("]");
}
}
Console.ReadLine();
}
}
either you can build up a Data Transfer Object that holds all these three variables instantiate it and then return it to your main function.
You could also make use of variables that are passed as references instead of by value and use the updated reference value. Read about pass by value type & reference type for c# and the ref keyword.
This is a question I have come across and failed
Suppose say
string str = "wordcounter";
One can easily find the Length using str.Length
However, is it possible in C# to get the number of letters, without using any inbuilt functions like Length, SubStr etc
you could write a loop and increment a counter inside this loop:
int numberOfLetters = 0;
foreach (var c in str)
{
numberOfLetters++;
}
// at this stage numberOfLetters will contain the number of letters
// that the string contains
there is also another way:
int numberOfLetters = str.ToCharArray().Length;
there is also another, even crazier way using the SysStringByteLen function which operates on a BSTR. Strings in .NET are layed out in memory by using a 4 byte integer containing the length of the string followed by that many 2 byte UTF-16 characters representing each character. This is similar to how BSTRs are stored. So:
class Program
{
[DllImport("oleaut32.dll")]
static extern uint SysStringByteLen(IntPtr bstr);
static void Main()
{
string str = "wordcounter";
var bstr = Marshal.StringToBSTR(str);
// divide by 2 because the SysStringByteLen function returns
// number of bytes and each character takes 2 bytes (UTF-16)
var numberOfLetters = SysStringByteLen(bstr) / 2;
Console.WriteLine(numberOfLetters);
}
}
Obviously doing something like this instead of using the built-in Length function should never be done in any real production code and the code shown here should not be taken seriously.
My answer is bit late, but I would like to post the same. Though all above mentioned solutions are correct, but I believe that the IL of the foreach does knows about the length of the iterable before iterating it. Talking of a pure solution, here's mine:
private int stringLength(string str) {
int length = 0;
bool done = false;
do {
try {
char c = str[length];
length++;
} catch (IndexOutOfRangeException) {
done = true;
}
} while(!done);
return length;
}
How about?
int myOwnGetStringLength(String str)
{
int count = 0;
foreach(Char c in str)
count++;
return count;
}
not very fast but yo can always loop and count the number of caracter contained.
int counter = 0;
foreach (var caracter in str)
{
counter ++;
}
class Program
{
static void Main(string[] args)
{
string Name = "He is palying in a ground.";
char[] characters = Name.ToCharArray();
StringBuilder sb = new StringBuilder();
for (int i = Name.Length - 1; i >= 0; --i)
{
sb.Append(characters[i]);
}
Console.Write(sb.ToString());
Console.Read();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter a string to find its lenght");
string ch = Console.ReadLine();
Program p = new Program();
int answer = p.run(ch);
Console.WriteLine(answer);
Console.ReadKey();
}
public int run(string ch)
{
int count = 0;
foreach (char c in ch)
{
count++;
}
return count;
}
}
My general solution involves without using 'foreach' or 'StringBuilder' (which are C# specific) or without catching any exception.
string str = "wordcounter";
str += '\0';
int x = 0;
while (str[x] != '\0')
x++;
Console.WriteLine(x); //Outputs 11
class Program
{
static void Main(string[] args)
{
string test = "test";
//string as char array:
//iterate through char collection
foreach (char c in test)
{
//do something
}
//access elements by index
Console.WriteLine("Contents of char array : {0}, {1}, {2}, {3}", test[0], test[1], test[2], test[3]);
Console.ReadKey();
}
}
namespace ConsoleApplication {
class Program {
static void Main(string[] args) {
string testString = "testing";
int x = 0;
foreach(char c in testString) {
x++;
}
Console.WriteLine("\nLength Of String:{0}", (x));
Console.Read();
}
}