Array searching in C# throwing error - c#

I'm playing around with C# trying to get the basics down pat, but I'm stumped on this odd error. I'm trying to search through an array of names, and then return the location of any matches. At the moment I'm just printing the name, but I'm able to get the location.
For some reason though, when I type a name I want to search for and hit enter, the program crashes saying "ArraySearch.exe has stopped working". Any idea whats wrong??
Pardon the nooby questions, I'm still new to this language/paradigm :p
Thanks! :)
using System;
public class Test
{
public static void Main()
{
string[] stringArray = {"Nathan", "Bob", "Tom"};
bool [] matches = new bool[stringArray.Length];
string searchTerm = Console.ReadLine();
for(int i = 1;i<=stringArray.Length;i++){
if (searchTerm == stringArray[i - 1]){
matches[i] = true;
}
}
for(int i = 1;i<=stringArray.Length;i++){
if (matches[i]){
Console.WriteLine("We found another " + stringArray[i - 1]);
}
}
}
}

i will reach 3, which will give Out of range exception here:
matches[i] = true;
This would be easy to spot using debugging. (Try to learn using it. Very useful)
matches has 3 elements so the index ranges from 0 to 2.

using System;
public class Test
{
public static void Main()
{
string[] stringArray = { "Nathan", "Bob", "Tom" };
bool[] matches = new bool[stringArray.Length];
string searchTerm = "Bob";
for (int i = 1; i <= stringArray.Length; i++)
{
if (searchTerm == stringArray[i - 1])
{
matches[i - 1] = true;
}
}
for (int i = 1; i <= stringArray.Length; i++)
{
if (matches[i - 1])
{
Console.WriteLine("We found another " + stringArray[i - 1]);
}
}
}
}
See the fix above. It was failing because the bool array does not have an item at index 3. 3 is 1 index more than its last index, i.e. 2.
Its indexes are 0,1,2. which in turn store 3 elements just as u require.
When looping through arrays it is best to get used to using the actual indexes.
So i would suggest looping from 0 until array.length - 1. That way u have a direct reference to every element in the array.

I would strongly suggest using lambda's for this kind of processing.
Much fewer lines and simple to understand.
For example:
using System;
using System.Linq;
namespace ConsoleApplication5
{
public class Test
{
public static void Main()
{
string[] stringArray = { "Nathan", "Bob", "Tom" };
bool exists = stringArray.Any(x => x.Equals("Nathan"));
Console.WriteLine(exists);
}
}
}
The above method call, Any(), does the search for you. There are many options to explore. You can replace Any() with First(), Last() etc. If i were you I would definitely explore the System.Linq library for these kind of operations on collections.
(Remember that an array is also a collection)

Related

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.

C# Local variable won't mutate in if statement

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();
}

Generate all combinations with unknown number of slots

I have a text file full of strings, one on each line. Some of these strings will contain an unknown number of "#" characters. Each "#" can represent the numbers 1, 2, 3, or 4. I want to generate all possible combinations (permutations?) of strings for each of those "#"s. If there were a set number of "#"s per string, I'd just use nested for loops (quick and dirty). I need help finding a more elegant way to do it with an unknown number of "#"s.
Example 1: Input string is a#bc
Output strings would be:
a1bc
a2bc
a3bc
a4bc
Example 2: Input string is a#bc#d
Output strings would be:
a1bc1d
a1bc2d
a1bc3d
a1bc4d
a2bc1d
a2bc2d
a2bc3d
...
a4bc3d
a4bc4d
Can anyone help with this one? I'm using C#.
This is actually a fairly good place for a recursive function. I don't write C#, but I would create a function List<String> expand(String str) which accepts a string and returns an array containing the expanded strings.
expand can then search the string to find the first # and create a list containing the first part of the string + expansion. Then, it can call expand on the last part of the string and add each element in it's expansion to each element in the last part's expansion.
Example implementation using Java ArrayLists:
ArrayList<String> expand(String str) {
/* Find the first "#" */
int i = str.indexOf("#");
ArrayList<String> expansion = new ArrayList<String>(4);
/* If the string doesn't have any "#" */
if(i < 0) {
expansion.add(str);
return expansion;
}
/* New list to hold the result */
ArrayList<String> result = new ArrayList<String>();
/* Expand the "#" */
for(int j = 1; j <= 4; j++)
expansion.add(str.substring(0,i-1) + j);
/* Combine every expansion with every suffix expansion */
for(String a : expand(str.substring(i+1)))
for(String b : expansion)
result.add(b + a);
return result;
}
I offer you here a minimalist approach for the problem at hand.
Yes, like other have said recursion is the way to go here.
Recursion is a perfect fit here, since we can solve this problem by providing the solution for a short part of the input and start over again with the other part until we are done and merge the results.
Every recursion must have a stop condition - meaning no more recursion needed.
Here my stop condition is that there are no more "#" in the string.
I'm using string as my set of values (1234) since it is an IEnumerable<char>.
All other solutions here are great, Just wanted to show you a short approach.
internal static IEnumerable<string> GetStrings(string input)
{
var values = "1234";
var permutations = new List<string>();
var index = input.IndexOf('#');
if (index == -1) return new []{ input };
for (int i = 0; i < values.Length; i++)
{
var newInput = input.Substring(0, index) + values[i] + input.Substring(index + 1);
permutations.AddRange(GetStrings(newInput));
}
return permutations;
}
An even shorter and cleaner approach with LINQ:
internal static IEnumerable<string> GetStrings(string input)
{
var values = "1234";
var index = input.IndexOf('#');
if (index == -1) return new []{ input };
return
values
.Select(ReplaceFirstWildCardWithValue)
.SelectMany(GetStrings);
string ReplaceFirstWildCardWithValue(char value) => input.Substring(0, index) + value + input.Substring(index + 1);
}
This is shouting out loud for a recursive solution.
First, lets make a method that generates all combinations of a certain length from a given set of values. Because we are only interested in generating strings, lets take advantage of the fact that string is immutable (see P.D.2); this makes recursive functions so much easier to implement and reason about:
static IEnumerable<string> GetAllCombinations<T>(
ISet<T> set, int length)
{
IEnumerable<string> getCombinations(string current)
{
if (current.Length == length)
{
yield return current;
}
else
{
foreach (var s in set)
{
foreach (var c in getCombinations(current + s))
{
yield return c;
}
}
}
}
return getCombinations(string.Empty);
}
Study carefully how this methods works. Work it out by hand for small examples to understand it.
Now, once we know how to generate all possible combinations, building the strings is easy:
Figure out the number of wildcards in the specified string: this will be our combination length.
For every combination, insert in order each character into the string where we encounter a wildcard.
Ok, lets do just that:
public static IEnumerable<string> GenerateCombinations<T>(
this string s,
IEnumerable<T> set,
char wildcard)
{
var length = s.Count(c => c == wildcard);
var combinations = GetAllCombinations(set, length);
var builder = new StringBuilder();
foreach (var combination in combinations)
{
var index = 0;
foreach (var c in s)
{
if (c == wildcard)
{
builder.Append(combination[index]);
index += 1;
}
else
{
builder.Append(c);
}
}
yield return builder.ToString();
builder.Clear();
}
}
And we're done. Usage would be:
var set = new HashSet<int>(new[] { 1, 2, 3, 4 });
Console.WriteLine(
string.Join("; ", "a#bc#d".GenerateCombinations(set, '#')));
And sure enough, the output is:
a1bc1d; a1bc2d; a1bc3d; a1bc4d; a2bc1d; a2bc2d; a2bc3d;
a2bc4d; a3bc1d; a3bc2d; a3bc3d; a3bc4d; a4bc1d; a4bc2d;
a4bc3d; a4bc4d
Is this the most performant or efficient implementation? Probably not but its readable and maintainable. Unless you have a specific performance goal you are not meeting, write code that works and is easy to understand.
P.D. I’ve omitted all error handling and argument validation.
P.D.2: if the length of the combinations is big, concatenting strings inside GetAllCombinations might not be a good idea. In that case I’d have GetAllCombinations return an IEnumerable<IEnumerable<T>>, implement a trivial ImmutableStack<T>, and use that as the combination buffer instead of string.

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
*/
}
}
}

Reading values out from an ArrayList in an independent function

I am having troubling reading my values out of an ArrayList. The compiler goes into the ReadOutFromArray function, but skips the Console.WriteLine(st)? Can anyone tell me where I went wrong. Been on it for a couple of hours chasing my tail. Thanks.
using System;
using System.IO;
using System.Collections.Generic;
using System.Collections;
using System.Text;
namespace BoolEx
{
class Program
{
static void Decision(ArrayList decis)
{
bool ans = true;
decis = new ArrayList();
//ArrayList aList = new ArrayList();
while (ans)
{
Console.WriteLine("1=True 0=False");
int x = Int32.Parse(Console.ReadLine());
if (x == 1)
{
ans = true;
}
else
{
ans = false;
}
if (ans == true)
{
ReadInArray(decis);
}
else
{
ReadOutArray(decis);
}
}
}
static void ReadInArray(ArrayList f)
{
f= new ArrayList();
Console.WriteLine("Enter in a name");
f.Add(Console.ReadLine());
}
static void ReadOutArray(ArrayList d)
{
d = new ArrayList();
ReadInArray(d);
foreach (string st in d)
{
Console.WriteLine(st);
}
}
static void Main(string[] args)
{
ArrayList g = new ArrayList();
Decision(g);
}
}
}
The problem is your ReadInArray method:
static void ReadInArray(ArrayList f)
{
f= new ArrayList();
Console.WriteLine("Enter in a name");
f.Add(Console.ReadLine());
}
In the first line of the method, you're basically saying, "I don't care what ArrayList reference was passed in - I'm going to overwrite the local variable f with a reference to a new ArrayList."
I suspect you meant something like this:
static void ReadInArray(ArrayList f)
{
f.Clear();
Console.WriteLine("Enter in a name");
f.Add(Console.ReadLine());
}
If you don't understand why that changes things, see my parameter passing article.
Other things you should consider:
If you're only going to read a single line, why not use something like this:
static string ReadNameFromUser()
{
Console.WriteLine("Enter in a name");
return Console.ReadLine();
}
The same sort of thing occurs elsewhere. Don't try to use collections for all your input and output. Returning a value is much clearer than populating a list which is passed into the method.
Given that you can obviously refer to generic collections (given your using directives) you should really consider using List<string> instead of ArrayList
Code like this:
if (x == 1)
{
ans = true;
}
else
{
ans = false;
}
... would be better written as
ans = (x == 1);
(The brackets are optional, but help readability.)
Code like this:
if (ans == true)
is better written as:
if (ans)
Although I do agree with everything Skeet has mentioned, it appears the poster is trying to understand some things and I think
Jon might have missed that.
First if all you want to do is fill a list and print it try this:
static void (main)
{
ArrayList l = new ArrayList();
FillMyList(l);
DisplayMyList(l);
}
public static void FillMyList(ArrayList temp)
{
for(int i = 0; i < 10; i++)
temp.Add(i);
}
public static void DisplayMyList(ArrayList temp)
{
foreach(int i in temp)
Console.WriteLine(i);
}
Second thing is take what Jon Skeet has mentioned and definately understand some things. Booleans are just true / false (unless you introduce the nullable types) but for now keep it simple.
ArrayList is really old school, it kind of suffers like the HashTable in that you can easily run into trouble adding different data types into the object (read up on boxing of data types and unboxing).
Finally, you should really replace anything with this System.Collection.ArrayList to System.Collections.Generic.List.
The list class is a generic class and is made available so that you don't have to deal with the issues that you could encounter when dealing with array lists or hash tables.
Edit
I noticed you were asking users to add items to the list. You can do this using a do while loop instead of the for loop I posted, something to this effect (note i have not tested any of this):
public static void FillMyList(ArrayList temp)
{
char c='y';
do {
Console.WriteLine("Enter a value");
int x = Int32.Parse(Console.ReadLine());
temp.Add(x);
Console.WriteLine("Continue adding numbers to list, if so type y");
char c = Console.ReadLine();
}while(c=='y' || c=='Y');
}
Again I am just giving you examples here, you will have to handle user input in case someone doesn't enter the correct information, exceptions, etc.

Categories

Resources