C# Local variable won't mutate in if statement - c#

I am quite new the C# and I have googled the answer. The closest answer I have found was this one. But it doesn't help me.
I am trying to write a function that finds the biggest number in a string using loops and splicing only. For some reason, when the condition is met, the local variable big won't mutate in the if statements. I have tried to debug it by setting big = 34 when I hit a space, but even then it won't mutate the local variable.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace parser
{
class Sub_parser
{
// function to find the greatest number in a string
public int Greatest(string uinput)
{
int len = uinput.Length;
string con1 = "";
int big = 0;
int m = 0;
// looping through the string
for (int i = 0; i < len; i++)
{
// find all the numbers
if (char.IsDigit(uinput[i]))
{
con1 = con1 + uinput[i];
}
// if we hit a space then we check the number value
else if (uinput[i].Equals(" "))
{
if (con1 != "")
{
m = int.Parse(con1);
Console.WriteLine(m);
if (m > big)
{
big = m;
}
}
con1 = "";
}
}
return big;
}
public static void Main(string[] args)
{
while (true)
{
string u_input = Console.ReadLine();
Sub_parser sp = new Sub_parser();
Console.WriteLine(sp.Greatest(u_input));
}
}
}
}

The problem comes from your check in this statement :
else if (uinput[i].Equals(" "))
uinput[i] is a char, while " " is a string : see this example
if you replace the double quotes by single quotes, it works fine...
else if (uinput[i].Equals(' '))
And, as stated by the comments, the last number will never be checked, unless your input string ends by a space. This leaves you with two options :
recheck again the value of con1 after the loop (which is not very good-looking)
Rewrite your method because you're a bit overdoing things, don't reinvent the wheel. You can do something like (using System.Linq):
public int BiggestNumberInString(string input)
{
return input.Split(null).Max(x => int.Parse(x));
}
only if you are sure of your input

When you give a number and a space in the keyboard you only read the number, no space.
So you have uinput="34".
Inside the loop, you check if the m > big only if uinput[i].Equals(" "). Which is never.
In general if you read a line, with numbers followed by space, it would ignore the last number.
One solution would be to append a " " into uinput, but i recommend splicing.
string[] numbers = uinput.Split(null);
Then iterate over the array.
Also, as said in another answer compare uinput[i].Equals(' ') because " "represents a string, and you were comparing a char with a string.

As Martin Verjans mentioned, in order to make your code work you have to edit it like in his example.
Although there is still a Problem if you input a single number. The output would then be 0.
I would go for this Method:
public static int Greatest(string uinput)
{
List<int> numbers = new List<int>();
foreach(string str in uinput.Split(' '))
{
numbers.Add(int.Parse(str));
}
return numbers.Max();
}

Related

Recommended way of checking if a certain string has a specified character more than once

Firstly I understand that there are several ways to do this and I do have some code which runs, but what I just wanted to find out was if anyone else has a recommended way to do this. Say I have a string which I already know that would have contain a specific character (a ‘,’ in this case). Now I just want to validate that this comma is used only once and not more. I know iterating through each character is an option but why go through all that work because I just want to make sure that this special character is not used more than once, I’m not exactly interested in the count per se. The best I could think was to use the split and here is some sample code that works. Just curious to find out if there is a better way to do this.
In summary,
I have a certain string in which I know has a special character (‘,’ in this case)
I want to validate that this special character has only been used once in this string
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var countOfIdentifiedCharacter = myStringToBeTested.Split(characterToBeEvaluated).Length - 1;
if (countOfIdentifiedCharacter == 1)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
You can use string's IndexOf methods:
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
string substringToFind = characterToBeEvaluated.ToString();
int firstIdx = myStringToBeTested.IndexOf(substringToFind, StringComparison.Ordinal);
bool foundOnce = firstIdx >= 0;
bool foundTwice = foundOnce && myStringToBeTested.IndexOf(substringToFind, firstIdx + 1, StringComparison.Ordinal) >= 0;
Try it online
You could use the LINQ Count() method:
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var countOfIdentifiedCharacter = myStringToBeTested.Count(x => x == characterToBeEvaluated);
if (countOfIdentifiedCharacter == 1)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
This is the most readable and simplest approach and is great if you need to know the exact count but for your specific case #ProgrammingLlama's answer is better in terms of efficiency.
Adding another answer using a custom method:
public static void Main()
{
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var characterAppearsOnlyOnce = DoesCharacterAppearOnlyOnce(characterToBeEvaluated, myStringToBeTested);
if (characterAppearsOnlyOnce)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
}
public static bool DoesCharacterAppearOnlyOnce(char characterToBeEvaluated, string stringToBeTested)
{
int count = 0;
for (int i = 0; i < stringToBeTested.Length && count < 2; ++i)
{
if (stringToBeTested[i] == characterToBeEvaluated)
{
++count;
}
}
return count == 1;
}
The custom method DoesCharacterAppearOnlyOnce() performs better than the method using IndexOf() for smaller strings - probably due to the overhead calling IndexOf. As the strings get larger the IndexOf method is better.

Counting duplicate chars in a C# string

I'm new to C# and trying to work out how to count the number of duplicates in a string. Example input and output would be:
"indivisibility" -> 1 # 'i' occurs six times
"Indivisibilities" -> 2 # 'i' occurs seven times and 's' occurs twice
"aA11" -> 2 # 'a' and '1'
"ABBA" -> 2 # 'A' and 'B' each occur twice
My code so far is as follows:
using System;
using System.Collections;
using System.Linq;
public class Kata
{
public static int DuplicateCount(string str)
{
Stack checkedChars = new Stack();
Stack dupChars = new Stack();
str = str.ToLower();
for (int i=1; i < str.Length; i++) {
var alreadyCounted = checkedChars.Contains(str[i]) && dupChars.Contains(str[i]);
if (!checkedChars.Contains(str[i])) {
checkedChars.Push(str[i]);
} else if (checkedChars.Contains(str[i])) {
dupChars.Push(str[i]);
} else if (alreadyCounted) {
break;
}
}
return dupChars.Count;
}
}
My approach is to loop through each character in the string. If it hasn't been seen before, to add it to a 'checkedChars' Stack (to keep track of it). If it's already been counted, add it to a 'dupChars' Stack. However, this is failing the tests. E.g:
aabbcde is the string, and the test fails with: Expected: 2 But Was: 1
Also when I console out errors, it appears that the checkedChars Stack is empty.
Can anyone spot where I have gone wrong please?
I'd suggest you use LINQ instead. It's a more suitable tool for the problem, and it results in much cleaner code:
class Program
{
static void Main(string[] args)
{
var word = "indivisibility";
Console.WriteLine($"{word} has {CountDuplicates(word)} duplicates.");
word = "Indivisibilities";
Console.WriteLine($"{word} has {CountDuplicates(word)} duplicates.");
word = "aA11";
Console.WriteLine($"{word} has {CountDuplicates(word)} duplicates.");
word = "ABBA";
Console.WriteLine($"{word} has {CountDuplicates(word)} duplicates.");
Console.ReadLine();
}
public static int CountDuplicates(string str) =>
(from c in str.ToLower()
group c by c
into grp
where grp.Count() > 1
select grp.Key).Count();
}
}
Here's the output:
indivisibility has 1 duplicates.
Indivisibilities has 2 duplicates.
aA11 has 2 duplicates.
ABBA has 2 duplicates.
Hope this helps.
You need to start the loop at int i = 0, because indexing start at 0 and not 1. So to get the first character you'll need to call str[0].
You can also remove the break as your code will never hit it, since the first 2 conditions are exactly the opposite of each other. Instead check first if alreadyCounted is true and use continue (not break as it will exit the loop entirely!) to skip to the next iteration, to avoid counting the same characters more than once.
you can use LINQ for this -
var str = "aabbcde";
var count = str.ToLower().GroupBy(x => x).Select(y => y).Where(z=>z.Count()>1).Count();
You can also use MoreLinq.CountBy:
using System;
using System.Linq;
using MoreLinq;
namespace ConsoleApp1
{
internal class Program
{
private static int CountDuplicateCharacters(string s)
{
return s?.CountBy(c => c).Where(kvp => kvp.Value > 1).Count() ?? 0;
}
private static void Main(string[] args)
{
foreach (var s in new string[] { "indivisibility", "Indivisibilities", "aA11", "ABBA" })
{
Console.WriteLine(s + ": " + CountDuplicateCharacters(s));
}
}
}
}
In case you do not want to differentiate between lower and upper case you need to supply an EqualityComparer as a second argument to CountBy.

A few problems with c# : the program doesn't read files from my array, having trouble with line.split

so I'm having trouble with the program recognizing the values of my array elements (The name 'a' does not exist in the current context) , plus i can't get line.split to work(I need it to read the next element after the ',' and it needs to loop for all books (it's a library program). Lastly i can't figure out how to change the "10" (i put the number at random, so it doesn't show me an error) in my for loop, so that the program stops after it read all the info from .txt. Here's the code:
EDIT : It doesn't show any more errors, it just crashes now. :(
using System;
using System.IO;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
foreach (string line in File.ReadAllLines(#"Duomenys.txt"))
{
string[] a = line.Split(',');
int ISBN = int.Parse(a[0]);
string BookName = a[1];
string Author = a[2];
string Genre = a[3];
string Publisher = a[4];
int PublishYear = int.Parse(a[5]);
int PageNumber = int.Parse(a[6]);
Console.WriteLine(PublishYear);
Console.WriteLine();
Console.ReadKey();
}
}
public void BookWithTheMostPages(int[] a)
{
int maxPages = 0;
string[] lines = File.ReadAllText(#"Duomenys.txt").Split('\n');
foreach (string line in lines)
{
{
Console.ReadLine();
if (a[6] > maxPages)
{
maxPages = a[6];
Console.WriteLine("Storiausios knygos pavadinimas: {0} , jos autorius(-ė): {1}", a[1], a[2]);
}
}
}
}
public void Publish(string[] a)
{
if (!File.Exists(#"Technologija.csv"))
File.Create(#"Technologija.csv").Dispose();
using (StreamWriter streamwrite = new StreamWriter(File.OpenWrite(#"Technologija.csv")))
{
if (a[2] == "Technologija")
{
streamwrite.WriteLine("\n ISBN : {0}, Pavadinimas: {1}, Autorius: {2}, Tipas: {3}, Leidykla: {4}, Išleidimo Metai: {5}, Puslapių skaičius: {6}", a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
}
}
}
public void Output(string[] a)
{
if (!File.Exists(#"Autoriai.csv"))
File.Create(#"Autoriai.csv").Dispose();
using (StreamWriter streamWriter = new StreamWriter(File.OpenWrite(#"Autoriai.csv")))
{
streamWriter.WriteLine("\n{0}", a[2]);
}
}
public void Publishyear(string[] a)
{
if (a[5] == "2014")
{
for (int j = 1; j <= 5; j++)
Console.WriteLine("\nKnygos ISBN: {0}, Pavadinimas {1}, Autorius {2}", a[0], a[1], a[2]);
}
}
}
}
Here's the .txt example:
9781408855669, Harry Potter and the Chamber of Secrets, Joanne K Rowling, Apysaka, Bloomsbury Publishing PLC, 1998, 270. (It's one line)
a and line are scoped to the static Main method (well, actually a is defined twicein Main, which isn't legal). They do not exist outside of there, unless you make them available, either by passing them in as parameters, or by making them available via fields. You should probably:
come up with more meaningful names; a will not help you
pass the value in as a parameter (IMO this would be cleaner than fields, but fields would work too)
decide whether you are working in instance or static context - at the moment you have both, but never instantiate an object, so you won't be able to call any of the methods
Note that the using and foreach should not be terminated like that ; you probably meant:
foreach (string line in File.ReadAllLines(#"Duomenys.txt"))
{
string[] a = line.Split(',');
...
}
(no need for the using / StreamReader)
'a' only exists in the main function. Like Marc said, you'll want to pass in 'a' as a parameter if you're using it in a different function.
So first line of the function:
public void BookWithTheMostPages() {
}
Should be:
public void BookWithTheMostPages(string[] a)
And should be called in the main function like this:
BookeWithTheMostPages(a);
That-a-ways the function "knows" what 'a' is.
Also, I notice that you're not telling your Main function to run any of the functions you wrote. The program runs everything inside the Main function, not just everything in the Main.cs file. So your 'Publishyear', 'Output', 'Publish', and 'BookWithTheMostPages' function simply aren't running.
Now in regards to your Split function not working here's 2 things:
You have already have something name 'a' in your program, you cannot name another variable by the same name. Make sense?
You must 'Split' into another array, since Split returns a series of strings
So it should look like this:
string[] splitLine = line.split(',');
Also these to lines are not correct:
int PublishYear = Convert.ToInt32(a[5]);
int PageNumber = Convert.ToInt32(a[6]);
If you're wanting to have the 'PublishYear' and 'PageNumber' functions to return an int, they cannot be void functions.
public int Publishyear() {
/*Write your code in here*/
return year;
}
Then later you can use the Function like this to get a value.
int i = Publishyear();
Same goes for your 'PageNumber' Function.
There are still a lot of little errors in the program I haven't mentioned and it would take forever to write down everyone with an explination, but for a beginner like yourself take it piece by piece. Follow a guideline like this:
Write down what the program is supposed to do on paper.
Write a small portion of code (couple lines)
Test it.
Repeat steps 2 and 3 until finished.
One last thing, get in the habit of naming your variables with more descriptive names. 'a' doesn't let a reader know at a glance what 'a' is. Write code that is easy for other people to read. I know at the beginning programming can seems very hard and confusing, but keep at it, don't give up. And little by little you'll get this whole programming things figured out.
Cheers!
Alright so first of all, remove the
using (StreamReader dn = new StreamReader(#"Duomenys.txt"));
if you are not using it. If you are reading the file with File.ReadAllLines you are not going to need it. Also, you are not using your foreach loop correctly. The way you want to go would be something like this:
foreach (string line in File.ReadAllLines(#"Duomenys.txt"))
{
string[] a = line.split(',');
int ISBN = Convert.ToInt32(a[0]);
string BookName = a[1];
string Author = a[2];
string Genre = a[3];
string Publisher = a[4];
int PublishYear = Convert.ToInt32(a[5]);
int PageNumber = Convert.ToInt32(a[6]);
}
What I fixed aswell is that you first create a string array named a, but then create a normal string named a which does not work. Also no need to set a size for the array, string.Split() does this automatically.
EDIT: To loop the file lines, assuming they are seperated by line terminators, you could do this:
string[] lines = File.ReadAllText(filename).Split('\n');
// '\n' as the regular line terminator
foreach (string line in lines)
{
// Your other code ...

How to find a pair of chars within a string in c# netMF?

This has probably (somewhere) been asked before, but can't find any documentation on it (i have looked!).
Say I had declared a string like:
String Test = "abcdefg";
How would i go about searching the string to see if I could see "cd" anywhere in the string by searching through the string in pairs, like:
{ab}{bc}{cd}{de}{ef}{fg}
That is, if I split each of the values up, and searched for a pair of chars next to each other? Is there a built in function for this?
I have thought about using a char array for this, but it seems to (logically) be very 'heavy'/'slow'. Would there be a better solution to search this string?
EDIT 1
Once I see this "cd", I would then need to doSomething() at that position (which I have already implemented by using the substring method.
Try this.
String.IndexOf(...) != -1
For more infö, read here.
Similar to the answer from Neo, but in a loop to get all instances within the string:
string Test = "abcdefgcd";
int index = Test.IndexOf("cd");
while (index > -1)
{
//DoSomething();
index = Test.IndexOf("cd", ++index);
}
The first IndexOf checks for the existence of what you want, whilst the second IndexOf (in the loop) checks for a match after the last index.
In the above we find two matches and then the loop ends.
There is no build in function that will do that.
having a for loop should do what you want.
something like that:
string str = string.empty;
for (i=0;i<ch.length;i++) {
if (i != ch.length) {
str += ch[i] + ch[i+1];
}
}
also you can use regex however that wont be fast either.
In order to optimize this on a large scale you can implement byte shifting.
The ASCII code of your string characters is your friend in this case, full working example below:
var yourString = "abcdefg";
var x = '\0';
for (var i = 0; i < yourString.Length; i++)
{
//check whether i+1 index is not out of range
if (i + 1 != yourString.Length)
{
var test = yourString[i + 1];
x = yourString[i];
if(x.ToString() + test.ToString() == "cd")
{
Console.Write("Found at position " + i)
}
}
}

C#: Get an integer representation of a string array

I am new to C# and I ran into the following problem (I have looked for a solution here and on google but was not successful):
Given an array of strings (some columns can possibly be doubles or integers "in string format") I would like to convert this array to an integer array.
The question only concerns the columns with actual string values (say a list of countries).
Now I believe a Dictionary can help me to identify the unique values in a given column and associate an integer number to every country that appears.
Then to create my new array which should be of type int (or double) I could loop through the whole array and define the new array via the dictionary. This I would need to do for every column which has string values.
This seems inefficient, is there a better way?
In the end I would like to do multiple linear regression (or even fit a generalized linear model, meaning I want to get a design matrix eventually) with the data.
EDIT:
1) Sorry for being unclear, I will try to clarify:
Given:
MAKE;VALUE ;GENDER
AUDI;40912.2;m
WV;3332;f
AUDI;1234.99;m
DACIA;0;m
AUDI;12354.2;m
AUDI;123;m
VW;21321.2;f
I want to get a "numerical" matrix with identifiers for the the string valued columns
MAKE;VALUE;GENDER
1;40912.2;0
2;3332;1
1;1234.99;0
3;0;0
1;12354.2;0
1;123;0
2;21321.2;1
2) I think this is actually not what I need to solve my problem. Still it does seem like an interesting question.
3) Thank you for the responses so far.
This will take all the possible strings which represent an integer and puts them in a List.
You can do the same with strings wich represent a double.
Is this what you mean??
List<int> myIntList = new List<int>()
foreach(string value in stringArray)
{
int myInt;
if(Int.TryParse(value,out myInt)
{
myIntList.Add(myInt);
}
}
Dictionary is good if you want to map each string to a key like this:
var myDictionary = new Dictionary<int,string>();
myDictionary.Add(1,"CountryOne");
myDictionary.Add(2,"CountryTwo");
myDictionary.Add(3,"CountryThree");
Then you can get your values like:
string myCountry = myDictionary[2];
But still not sure if i'm helping you right now. Do you have som code to specify what you mean?
I'm not sure if this is what you are looking for but it does output the result you are looking for, from which you can create an appropriate data structure to use. I use a list of string but you can use something else to hold the processed data. I can expand further, if needed.
It does assume that the number of "columns", based on the semicolon character, is equal throughout the data and is flexible enough to handle any number of columns. Its kind of ugly but it should get what you want.
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication3
{
class StringColIndex
{
public int ColIndex { get; set; }
public List<string> StringValues {get;set;}
}
class Program
{
static void Main(string[] args)
{
var StringRepresentationAsInt = new List<StringColIndex>();
List<string> rawDataList = new List<string>();
List<string> rawDataWithStringsAsIdsList = new List<string>();
rawDataList.Add("AUDI;40912.2;m");rawDataList.Add("VW;3332;f ");
rawDataList.Add("AUDI;1234.99;m");rawDataList.Add("DACIA;0;m");
rawDataList.Add("AUDI;12354.2;m");rawDataList.Add("AUDI;123;m");
rawDataList.Add("VW;21321.2;f ");
foreach(var rawData in rawDataList)
{
var split = rawData.Split(';');
var line = string.Empty;
for(int i= 0; i < split.Length; i++)
{
double outValue;
var isNumberic = Double.TryParse(split[i], out outValue);
var txt = split[i];
if (!isNumberic)
{
if(StringRepresentationAsInt
.Where(x => x.ColIndex == i).Count() == 0)
{
StringRepresentationAsInt.Add(
new StringColIndex { ColIndex = i,
StringValues = new List<string> { txt } });
}
var obj = StringRepresentationAsInt
.First(x => x.ColIndex == i);
if (!obj.StringValues.Contains(txt)){
obj.StringValues.Add(txt);
}
line += (string.IsNullOrEmpty(line) ?
string.Empty :
("," + (obj.StringValues.IndexOf(txt) + 1).ToString()));
}
else
{
line += "," + split[i];
}
}
rawDataWithStringsAsIdsList.Add(line);
}
rawDataWithStringsAsIdsList.ForEach(x => Console.WriteLine(x));
Console.ReadLine();
/*
Desired output:
1;40912.2;0
2;3332;1
1;1234.99;0
3;0;0
1;12354.2;0
1;123;0
2;21321.2;1
*/
}
}
}

Categories

Resources