I have a program that is to calculate taxes for payroll. I need a for loop to write the last name, first name, dept, rate, hours, earnings, fica, fedtax, statetax and netpay. I'm not thrown any errors when I run the program and can't seem to find why my output only displays the last name. There are two .txt files, one is blank for output and the other is listed below.
This is the data content of my .txt file:
Adams Paul 3 9.75 40.00
Allen Cindy 2 11.45 48.00
Allen Sarah 4 10.30 40.00
Baker John 1 22.00 43.25
Baker Toni 1 12.65 40.00
Baldwin Cindy 2 7.90 25.50
Carson Robert 1 8.35 52.50
Freeman Sally 4 15.25 40.00
Garfield James 3 22.00 40.00
Grimes Kerri 3 16.50 35.00
Harris Joan 2 18.65 51.00
Harris John 2 9.00 47.50
Lawson LeAnn 4 17.85 40.00
Mason Debbie 4 22.00 41.50
Masters Kenneth 3 16.10 40.25
Patterson Roseanne 2 13.70 38.00
Peterson Paul 2 22.00 44.00
Randall Michael 3 8.00 41.00
Rogers Sherry 1 16.50 30.00
Shepard Steven 3 10.90 45.50
This is my code:
using System;
using System.IO;
using System.Text.RegularExpressions;
using LibUtil;
classPayRoll
{
const double FICA_RATE = 0.07;
const double FED_TAX_RATE = 0.22;
const double STATE_TAX_RATE = 0.05;
const string INPUT_FILE_NAME = "PayrollDat.Txt";
const string OUTPUT_FILE_NAME = "PayrollReport.Txt";
static uint numOfEmployees;
static string[] lastNameArray = new string[51], firstNameArray = new string[51];
static uint[] deptArray = new uint[51];
static double[] rateArray = new double[51], hoursArray = new double[51];
static double[] earningsArray = new double[51], ficaArray = new double[51];
static double[] fedTaxArray = new double[51], stateTaxArray = new double[51];
static double[] netPayArray = new double[51];
static StreamReader fileIn;
static StreamWriter fileOut;
static void Main()
{
OpenFiles();
InputData();
CalcDetailPayroll();
PrintReport();
CloseFiles();
}
static void OpenFiles()
{
if (File.Exists(INPUT_FILE_NAME))
{
fileIn = File.OpenText(INPUT_FILE_NAME);
Console.WriteLine("{0} was opened", INPUT_FILE_NAME);
}
else
{
Console.WriteLine("Error: {0} does not exist\n", INPUT_FILE_NAME);
ConsoleApp.Exit();
}
fileOut = File.CreateText(OUTPUT_FILE_NAME);
if (File.Exists(OUTPUT_FILE_NAME))
Console.WriteLine("{0} was created\n", OUTPUT_FILE_NAME);
else
{
Console.WriteLine("Error: {0} could not be created\n", OUTPUT_FILE_NAME);
ConsoleApp.Exit();
}
}
static void ParseLineIn(string lineIn, uint i)
{
string[] words = new string[5];
lineIn = lineIn.Trim();
while (Regex.IsMatch(lineIn, "[ ]{2}"))
lineIn = lineIn.Replace(" ", " ");
words = lineIn.Split(' ');
lastNameArray[i] = words[0];
i = 0;
while (i <= numOfEmployees)
{
lastNameArray[i] = words[0];
firstNameArray[i] = words[1];
deptArray[i] = uint.Parse(words[2]);
rateArray[i] = double.Parse(words[3]);
hoursArray[i] = double.Parse(words[4]);
i++;
}
//Add code to read in data into remaining arrays
}
static void InputData()
{
uint i;
string lineIn;
i = 0;
while ((lineIn = fileIn.ReadLine()) != null)
{
i++;
ParseLineIn(lineIn, i);
}
numOfEmployees = i;
}
static void CalcDetailPayroll()
{
uint i;
double basePay, ovtPay;
for (i = 1; i <= numOfEmployees; i++)
{
if (hoursArray[i] <= 40.0)
{
basePay = Math.Round(hoursArray[i] * rateArray[i]); //Calculate base pay
ovtPay = 0.00;
}
else
{
basePay = Math.Round(40 * rateArray[i]); //Calculate base pay
ovtPay = Math.Round(rateArray[i] * (hoursArray[i] - 40.0) * 1.5); //Calculate overtime pay
}
//Calculate earnings, fica, fedTax, stateTax, and netPay
earningsArray[i] = basePay + ovtPay;
ficaArray[i] = earningsArray[i] * FICA_RATE;
fedTaxArray[i] = earningsArray[i] * fedTaxArray[i];
stateTaxArray[i] = earningsArray[i] * STATE_TAX_RATE;
netPayArray[i] = earningsArray[i] - (ficaArray[i] + fedTaxArray[i] + stateTaxArray[i]);
}
}
static double Total(double[] doubleArray)
{
uint i;
double total = 0.0;
for (i = 1; i <= numOfEmployees; i++) ;
total += earningsArray[i];
return total;
}
static double Mean(double[] doubleArray)
{
uint i;
double sum = 0.0;
for (i = 1; i <= numOfEmployees; i++)
sum += doubleArray[i];
return sum / numOfEmployees;
}
static double Max(double[] doubleArray)
{
uint i;
double max;
max = doubleArray[1];
for (i = 2; i <= numOfEmployees; i++)
if (doubleArray[i] > max)
max = doubleArray[i];
return max;
}
static double Min(double[] doubleArray)
{
uint i;
double min;
double max;
min = doubleArray[1];
for (i = 2; i <= numOfEmployees; i++)
if (doubleArray[i] < min)
max = doubleArray[i];
return min;
}
static void PrintReport()
{
uint i;
fileOut.WriteLine(" Payroll Report ");
fileOut.WriteLine();
fileOut.WriteLine(" Last Name First Name Dept Rate Hours Earnings FICA Fed Tax State Tax Net Pay ");
fileOut.WriteLine("--------------- --------------- ---- ----- ----- --------- --------- --------- --------- ---------");
for (i = 1; i <= numOfEmployees; i++)
{
fileOut.WriteLine("{0,-9} {1,9} {2,9} {3,9} {4,9} {5,9} {6,9} {7,9} {8,9} {9,9}",
lastNameArray[i], firstNameArray[i], deptArray[i], rateArray[i],hoursArray[i],earningsArray[i],
ficaArray[i],fedTaxArray[i],stateTaxArray[i],netPayArray[i]);
}
//Create for loop to display last name, firstname, dept, rate, hours, earnings, fica, fedTax, stateTax, and netPay
fileOut.WriteLine(" --------- --------- --------- --------- ---------");
fileOut.WriteLine("{0,-49}{1,9:n} {2,9:n} {3,9:n} {4,9:n} {5,9:n}",
"Total", Total(earningsArray), Total(ficaArray),
Total(fedTaxArray), Total(stateTaxArray), Total(netPayArray));
fileOut.WriteLine("{0,-49}{1,9:n} {2,9:n} {3,9:n} {4,9:n} {5,9:n}",
"Mean", Mean(earningsArray), Mean(ficaArray),
Mean(fedTaxArray), Mean(stateTaxArray), Mean(netPayArray));
fileOut.WriteLine("{0,-49}{1,9:n} {2,9:n} {3,9:n} {4,9:n} {5,9:n}",
"Maximum", Max(earningsArray), Max(ficaArray),
Max(fedTaxArray), Max(stateTaxArray), Max(netPayArray));
fileOut.WriteLine("{0,-49}{1,9:n} {2,9:n} {3,9:n} {4,9:n} {5,9:n}",
"Minimum", Min(earningsArray), Min(ficaArray),
Min(fedTaxArray), Min(stateTaxArray), Min(netPayArray));
}
static void CloseFiles()
{
fileIn.Close(); fileOut.Close();
}
}
You should change the ParseLineIn method to use the index passed from the caller. Actually you are setting always the same index when you set the i to zero
static void ParseLineIn(string lineIn, uint i)
{
string[] words = new string[5];
lineIn = lineIn.Trim();
while (Regex.IsMatch(lineIn, "[ ]{2}"))
lineIn = lineIn.Replace(" ", " ");
words = lineIn.Split(' ');
lastNameArray[i] = words[0];
// i = 0;
// No loop needed, you are reading one line of data and setting
// the appropriate index in the arrays
// while (i <= numOfEmployees)
//{
lastNameArray[i] = words[0];
firstNameArray[i] = words[1];
deptArray[i] = uint.Parse(words[2]);
rateArray[i] = double.Parse(words[3]);
hoursArray[i] = double.Parse(words[4]);
// i++;
//}
}
Also notice that your Total method has an error in this line
for (i = 1; i <= numOfEmployees; i++) ;
remove the semicolon at the end of the for loop to allow the execution of the line the makes the sum.
Said all this, I really suggest you to discard this array approach and build a proper class that represent your data and collect the information in a List of such data. Actually your code allows only files with 50 lines and please remember that array in NET start at index zero.
Related
I have one dll application. In this application I am extacting some values.There in information about extraction.
.
and I wrote c# code from this link guide to calculate digit number. and I will compare it. Below code I wrote for c# to calculate
private static int[] _weights = { 7, 3, 1 };
private static SortedDictionary<char, int> GetMappedDictionary()
{
string charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
SortedDictionary<char, int> mappedValues = new SortedDictionary<char, int>();
char[] charArr = charset.ToCharArray();
for (int i = 0; i < charArr.Length; ++i)
{
mappedValues[charArr[i]] = i;
}
mappedValues['<'] = 0;
return mappedValues;
}
private static int MrzComputeWeight(string line, int start, int end)
{
int sum = 0;
SortedDictionary<char, int> mappedValues = GetMappedDictionary();
for (int i = start, j = 0; i <= end; ++i, ++j)
{
var a = mappedValues[(line)[i]];
var b = _weights[j % 3];
sum += a *b;
}
return sum;
}
private static bool MrzCheckValidty(string line, int start, int end,int indexDigit)
{
int weight = MrzComputeWeight(line, start, end);
return (weight % 10) == Int32.Parse(line.Substring(indexDigit, 1));
}
Now It works for all test examples but It doesn't work for
IDUTOBE01124128TEST1234V<<<<<<
here document id is BE0112412 and when I calculate it , it gives me 4 as result but in mrz check digit is 8 . And this mrz is real mrz so 8 must be correct. Why this is not working for this MRZ even it works for anothers I tried?
Thanks in advance
I check your case and it gave 8 when you have letter O and it gave 4 when you have number 0.
Here is complete python code checkdigit.py:
#!/usr/bin/python3
import sys
def getcharvalue(c):
if c >= '0' and c <= '9':
return ord(c) - ord('0')
if c >= 'A' and c <= 'Z':
return ord(c) - ord('A') + 10
if c == '<':
return 0
def calc_checkdigit(data):
multipliers = [7, 3, 1]
s = 0
for idx,digit in enumerate(data):
n = getcharvalue(digit) * multipliers[idx % len(multipliers)]
s += n
cdigit = s % 10
return cdigit
data = sys.argv[1]
cdigit = calc_checkdigit(data)
print(cdigit)
Test run:
./checkdigit.py "BEO112412" # this prints 8
./checkdigit.py "BE0112412" # this prints 4
I got stuck in creating an algorithm that creates sets of 4 characters from two strings, two characters from one string and two from other string.
Example:
String one: FIRSTNAME
String two: LASTNAME
and the result that I expect is to get 10 sets of 4 characters like this: FILA, RSST, TNNA, AMME, EFLA and so on until we get 10 combinations like this.
this is the code that I made
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Name");
string name = Console.ReadLine();
Console.WriteLine("Lastname");
string lastname = Console.ReadLine();
int i;
var nchars = name.ToCharArray();
var pchars = lastname.ToCharArray();
for (i = 0; i <= 10; i++){
int ctr0;
int ctr;
int ctr2;
for (ctr = 0, ctr2 = 1, ctr0 = 1;
ctr < 10;
ctr0++, ctr = ctr + 2, ctr2 = ctr2 + 2) {
Console.WriteLine("{0}{1}{2}{3}{4}",
ctr0,
nchars[ctr],
nchars[ctr2],
pchars[ctr],
pchars[ctr2]);
}
}
}
}
and the output is good so far because I get
1FILA
2RSST
3TNNA
4AMME
but it stops when the string ends and instead of getting 10 combinations I get only 4.. what can I do?
Am I doing it wrong?
Or adding some Enumerable love.
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Name");
string name = Console.ReadLine();
Console.WriteLine("Lastname");
string lastname = Console.ReadLine();
// set the number of required sets and size
const int sets = 10;
const int size = 2;
// make both inputs long enough
var input1 = string.Concat(Enumerable.Repeat(name, (Math.Abs((sets * size) / name.Length) + 1)));
var input2 = string.Concat(Enumerable.Repeat(lastname, (Math.Abs((sets * size) / lastname.Length) + 1)));
// enumerate the index so we can substring the inputs.
var results = Enumerable.Range(0, sets)
.Select(x => $"{x + 1}{input1.Substring(x * size, size)}{input2.Substring(x * size, size)}");
// optional write to console
foreach(var result in results)
{
Console.WriteLine(result);
}
}
}
Trying to rectify your alogrithm, I think this is what you should try:
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Name");
string name = "FIRSTNAME";
Console.WriteLine("Lastname");
string lastname = "LASTNAME";
int i;
var nchars = name.ToCharArray();
var pchars = lastname.ToCharArray();
var ncharsCount = nchars.Length;
var pcharsCount = pchars.Length;
//for (i=0;i<=10;i++){
int ctr0;
int ctr;
int ctr2;
for (ctr = 0, ctr2 = 1, ctr0=1; ctr0 < 10 ;ctr0++, ctr++,ctr2++){
Console.WriteLine("{0}{1}{2}{3}{4}", ctr0,nchars[ctr%ncharsCount],nchars[ctr2%ncharsCount],pchars[ctr%pcharsCount],pchars[ctr2%pcharsCount]);
}
//}
}
}
Let's split the initial problem into several easier ones:
CircularSubstring, e.g. for value = "12345", index = 4, length = 3 we get "512"
MyGemerator which generate "FILA", "RSST" etc.
Final output in the required format
Code:
private static String CircularSubstring(string value, int index, int length) {
StringBuilder sb = new StringBuilder(length);
// + + value.Length) % value.Length -
// .Net can return negative remainder when we want it to be in [0..value.Length)
for (int i = 0; i < length; ++i)
sb.Append(value[((index + value.Length + i) % value.Length + value.Length) % value.Length]);
return sb.ToString();
}
private static IEnumerable<string> MyGenerator(string left, string right, int size) {
for (int i = 0; ; i += size)
yield return CircularSubstring(left, i, size) + CircularSubstring(right, i, size);
}
Then we are ready to generate a report in required format:
string one = "FIRSTNAME";
string two = "LASTNAME";
int size = 2; // chunks of size 2 from each (one, two) strings
int take = 10; // 10 chunks to generate
string report = string.Join(Environment.NewLine, MyGenerator(one, two, size)
.Take(take)
.Select((item, index) => $"{index + 1}{item}")
);
Console.Write(report);
Outcome:
1FILA
2RSST
3TNNA
4AMME
5EFLA
6IRST
7STNA
8NAME
9MELA
10FIST
More demo:
Console.Write(string.Join(Environment.NewLine, MyGenerator("Stack", "Overflow", 3)
.Take(12)
.Select((item, index) => $"{index + 1,2}. {item}")
));
Outcome:
1. StaOve
2. ckSrfl
3. tacowO
4. kStver
5. ackflo
6. StawOv
7. ckSerf
8. taclow
9. kStOve
10. ackrfl
11. StaowO
12. ckSver
So my homework is I have to take two numbers from the user then I have to write out the odd numbers in that interval.But the code under doesn't work. It writes out "TrueFalseTrueFalse".
int szam;
int szam2=0;
int szam3=0;
int szam4=0;
Console.Write("Please give a number:");
szam = Convert.ToInt32(Console.ReadLine());
Console.Write("Please give another number:");
szam2 = Convert.ToInt32(Console.ReadLine());
if (szam>szam2)
{
for (szam3=szam, szam4 = szam2; szam4 < szam3; szam4++)
{
Console.Write(szam2 % 2==1);
}
}
else
{
for (szam3 = szam, szam4 = szam2; szam3 < szam4; szam3++)
{
Console.Write(szam3 % 2 ==1);
}
}
So if the two numbers would be 0 and 10, the program has to write out 1, 3, 5, 7, and 9
I would be careful when naming your variables yes its a small piece of code but it gets confusing to people trying to read it.
Based on the requirement, I would guess you want all the odd numbers given a certain range.
const string comma = ",";
static void Main(string[] args)
{
int start = getNumber();
int end = getNumber();
if(start > end)
{
int placeHolder = end;
end = start;
start = placeHolder;
}
string delimiter = string.Empty;
for(int i = start; i < end; i++)
{
if(i % 2 == 1)
{
Console.Write(string.Concat(delimiter,i.ToString()));
delimiter = comma;
}
}
Console.ReadLine();//otherwise you wont see the result
}
static int getNumber()
{
Console.Write("Please enter a number:");
string placeHolder = Console.ReadLine();
int toReturn = -1;
if (int.TryParse(placeHolder, out toReturn))
return toReturn;
return getNumber();
}
as Juharr mentioned in the comments, you need to check the result to print the actual number.
Width Linq you can write:
int szam = 20;
int szam2= 30;
var odds = Enumerable.Range(szam2 > szam ? szam : szam2, Math.Abs(szam-szam2))
.Where(x=>x % 2 != 0);
outputs:
21
23
25
27
29
// so we create a range from low to high (Enumerable.Range(..)
// take only the odd values (x % 2 != 0)
simply wrap it in string.Join to make a single string:
string text = String.Join(",",Enumerable.Range(szam2 > szam ? szam :
szam2,Math.Abs(szam-szam2))
.Where(x=>x % 2 != 0));
I'm studying coding and I'm on project 8 of project euler.
I was able to show the product "5832" for four adjacent digits when I'm using my code however when I use it on 13 digits, it doesn't work. My code is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace practice
{
class Program
{
static void Main(string[] args)
{
const string number = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
string input1, input2, input3, input4, input5;
string input6, input7, input8, input9, input10;
string input11, input12, input13;
int convert1, convert2, convert3, convert4, convert5;
int convert6, convert7, convert8, convert9, convert10;
int convert11, convert12, convert13;
convert1 = convert2 = convert3 = convert4 = convert5 = convert6 = convert7 = convert8 = 0;
convert9 = convert10 = convert11 = convert12 = convert13 = 0;
int counter;
int product = 0;
int largest = 0;
int length = number.Length - 13;
for (counter = 1; counter <= length; counter++)
{
input1 = number.Substring(counter, 1);
input2 = number.Substring(counter+1, 1);
input3 = number.Substring(counter+2, 1);
input4 = number.Substring(counter+3, 1);
input5 = number.Substring(counter+4, 1);
input6 = number.Substring(counter+5, 1);
input7 = number.Substring(counter+6, 1);
input8 = number.Substring(counter+7, 1);
input9 = number.Substring(counter+8, 1);
input10 = number.Substring(counter+9, 1);
input11 = number.Substring(counter+10, 1);
input12 = number.Substring(counter+11, 1);
input13 = number.Substring(counter+12, 1);
convert1 = Convert.ToInt32(input1);
convert2 = Convert.ToInt32(input2);
convert3 = Convert.ToInt32(input3);
convert4 = Convert.ToInt32(input4);
convert5 = Convert.ToInt32(input5);
convert6 = Convert.ToInt32(input6);
convert7 = Convert.ToInt32(input7);
convert8 = Convert.ToInt32(input8);
convert9 = Convert.ToInt32(input9);
convert10 = Convert.ToInt32(input10);
convert11 = Convert.ToInt32(input11);
convert12 = Convert.ToInt32(input12);
convert13 = Convert.ToInt32(input13);
product = convert1 * convert2 * convert3 * convert4 * convert5 * convert6
* convert7 * convert8 * convert9 * convert10 * convert11
* convert12 * convert13;
if (largest < product) { largest = product; }
}
Console.WriteLine("The largest number is {0}", largest);
Console.ReadKey();
}
}
}
It doesn't show the correct answer which I find daunting. The next steps
I did is:
1. Check the last 13 digits of my variables to check if it loops and multiplies correctly "0420420752963450".
2. Check if it works with the first four numbers and first five numbers which are surprisingly correct.
3. Studied how others have done it.
4. Links used:
Homework in Java. Find the largest product of five consecutive digits
http://www.mathblog.dk/solution-to-problem-8-of-project-euler/
I seem to not get it. Please guide me on seeing my mistake. Thank you.
Your product variable is int and you parse your consecutive numbers to int. Max value for integer is 2,147,483,647. So when you multiply 13 numbers it's quite possible you will exceed the limit and the value will overflow giving incorrect result. Perhaps, consider using BigInteger instead.
What about something like this:
[Test]
public void Test()
{
const string number = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
int index = 0;
int largest = 0;
var largestString = "";
const int length = 13;
while (index + length <= number.Length)
{
var substring = number.Substring(index, length);
var product = ProductOfEachNumber(substring);
if (product > largest)
{
largestString = substring;
largest = product;
}
index++;
}
Console.WriteLine("The largest number is {0}", largest);
Console.WriteLine("The largest number string is {0}", largestString);
}
[Test]
public void TestSubstring()
{
var res = ProductOfEachNumber("9989");
res.Should().Be(5832);
}
private static int ProductOfEachNumber(string substring)
{
return substring.Aggregate(1, (current, c) => current*Int32.Parse(c.ToString()));
}
Gives output:
The largest number is 2091059712
The largest number string is 9781797784617
Try this one, let me know. You have to modify it.
static void Main(string[] args)
{
Stopwatch sw = Stopwatch.StartNew();
int x = Largest();
Console.WriteLine(x);
Console.WriteLine("Time used (float): {0} ms", sw.Elapsed.TotalMilliseconds);
Console.WriteLine("Time used (rounded): {0} ms", sw.ElapsedMilliseconds);
Console.ReadKey();
}
public static int Largest()
{
string p = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
int largest = 0;
int numm = 0;
for (int i = 0; i < p.Length - 4; i++)
{
numm = int.Parse(p.Substring(i, 1)) *
int.Parse(p.Substring(i + 1, 1)) *
int.Parse(p.Substring(i + 2, 1)) *
int.Parse(p.Substring(i + 3, 1)) *
int.Parse(p.Substring(i + 4, 1));
if (numm > largest)
{
largest = numm;
}
}
return largest;
}
I'm trying to get my head around a problem of identifying the best match of English words from a dictionary file to a given string.
For example ("lines" being a List of dictionary words):
string testStr = "cakeday";
for (int x= 0; x<= testStr.Length; x++)
{
string test = testStr.Substring(x);
if (test.Length > 0)
{
string test2 = testStr.Remove(counter);
int count = (from w in lines where w.Equals(test) || w.Equals(test2) select w).Count();
Console.WriteLine("Test: {0} / {1} : {2}", test, test2, count);
}
}
Gives the output:
Test: cakeday / : 0
Test: akeday / c : 1
Test: keday / ca : 0
Test: eday / cak : 0
Test: day / cake : 2
Test: ay / caked : 1
Test: y / cakeda : 1
Obviously "day / cake" is the best fit for the string however if I were to introduce a 3rd word into the string e.g "cakedaynow" it doesnt work so well.
I know the example is primitive, its more a proof of concept and was wondering if anyone had any experience with this type of string analysis?
Thanks!
You'll want to research the class of algorithms appropriate to what you're trying to do. Start with Approximate string matching on Wikipedia.
Also, here's a Levenshtein Edit Distance implementation in C# to get you started:
using System;
namespace StringMatching
{
/// <summary>
/// A class to extend the string type with a method to get Levenshtein Edit Distance.
/// </summary>
public static class LevenshteinDistanceStringExtension
{
/// <summary>
/// Get the Levenshtein Edit Distance.
/// </summary>
/// <param name="strA">The current string.</param>
/// <param name="strB">The string to determine the distance from.</param>
/// <returns>The Levenshtein Edit Distance.</returns>
public static int GetLevenshteinDistance(this string strA, string strB)
{
if (string.IsNullOrEmpty(strA) && string.IsNullOrEmpty(strB))
return 0;
if (string.IsNullOrEmpty(strA))
return strB.Length;
if (string.IsNullOrEmpty(strB))
return strA.Length;
int[,] deltas; // matrix
int lengthA;
int lengthB;
int indexA;
int indexB;
char charA;
char charB;
int cost; // cost
// Step 1
lengthA = strA.Length;
lengthB = strB.Length;
deltas = new int[lengthA + 1, lengthB + 1];
// Step 2
for (indexA = 0; indexA <= lengthA; indexA++)
{
deltas[indexA, 0] = indexA;
}
for (indexB = 0; indexB <= lengthB; indexB++)
{
deltas[0, indexB] = indexB;
}
// Step 3
for (indexA = 1; indexA <= lengthA; indexA++)
{
charA = strA[indexA - 1];
// Step 4
for (indexB = 1; indexB <= lengthB; indexB++)
{
charB = strB[indexB - 1];
// Step 5
if (charA == charB)
{
cost = 0;
}
else
{
cost = 1;
}
// Step 6
deltas[indexA, indexB] = Math.Min(deltas[indexA - 1, indexB] + 1, Math.Min(deltas[indexA, indexB - 1] + 1, deltas[indexA - 1, indexB - 1] + cost));
}
}
// Step 7
return deltas[lengthA, lengthB];
}
}
}
Why not:
Check all the strings inside the search word extracting from current search position to all possible lengths of the string and extract all discovered words. E.g.:
var list = new List<string>{"the", "me", "cat", "at", "theme"};
const string testStr = "themecat";
var words = new List<string>();
var len = testStr.Length;
for (int x = 0; x < len; x++)
{
for(int i = (len - 1); i > x; i--)
{
string test = testStr.Substring(x, i - x + 1);
if (list.Contains(test) && !words.Contains(test))
{
words.Add(test);
}
}
}
words.ForEach(n=> Console.WriteLine("{0}, ",n));//spit out current values
Output:
theme, the, me, cat, at
Edit
Live Scenario 1:
For instance let's say you want to always choose the longest word in a jumbled sentence, you could read from front forward, reducing the amount of text read till you are through. Using a dictionary makes it much easier, by storing the indexes of the discovered words, we can quickly check to see if we have stored a word containing another word we are evaluating before.
Example:
var list = new List<string>{"the", "me", "cat", "at", "theme", "crying", "them"};
const string testStr = "themecatcryingthem";
var words = new Dictionary<int, string>();
var len = testStr.Length;
for (int x = 0; x < len; x++)
{
int n = len > 28 ? 28 : len;//assuming 28 is the maximum length of an english word
for(int i = (n - 1); i > x; i--)
{
string test = testStr.Substring(x, i - x + 1);
if (list.Contains(test))
{
if (!words.ContainsValue(test))
{
bool found = false;//to check if there's a shorter item starting from same index
var key = testStr.IndexOf(test, x, len - x);
foreach (var w in words)
{
if (w.Value.Contains(test) && w.Key != key && key == (w.Key + w.Value.Length - test.Length))
{
found = true;
}
}
if (!found && !words.ContainsKey(key)) words.Add(key, test);
}
}
}
}
words.Values.ToList().ForEach(n=> Console.WriteLine("{0}, ",n));//spit out current values
Output:
theme, cat, crying, them