Wish to change a string[] variable depending on an int value - c#

i am new to c# and i have been trying to make a string[] that changes its contents depending on the int value of a different variable. i've tried switches and ifs but when i try to call the variable afterwards the program states that the variable does not exist in current context.
Im sorry for the bad description but here's a sample code regarding what i mean.
int flag = 0; //Value Changes
if (flag == 1)
{
string[] mainoptions = {"Return"};
}
else if (flag == 0)
{
string[] mainoptions = { "Grab Shovel", "Return" };
}
WriteLine(mainoptions); //The name 'mainoptions' does not exist in current context

For the vast majority of cases, any variables (eg. string name; or string name = "Roger";) that are created inside curly braces { } can only be accessed using their identifier from inside those braces.
Take this example:
int a = 0;
if (condition)
{
int b = 1;
}
Console.WriteLine(a); // can see the 'a' variable -> works fine
Console.WriteLine(b); // can NOT see the 'b' variable -> compilation error
The variable a can be accessed from the "main scope" (for lack of a better term), and also inside the if statement because the if statement defines a sub-scope, per se.
Variable b however, can only be accessed from within the if statement it was declared in, and also any sub-scopes that might occur inside there. It can NOT be accessed outside that if statement, because as soon as the program exits the block (reaches the closing brace }) you can imagine that variable b's reference is deleted.
With that, you can edit your program to define the variable mainoptions outside the if statements, and that will solve your issue

Let's get to the bottom of this:
You didn't declare a variable/property behind the if-construction. Anything that is declared in a logical construct does not exist for the compiler behind it. You've probably seen this before in the "access level" here: link.
If you want to print the variable array in a logical construct, you should do it like this:
if (a == someValue1)
{
string[] b = { "Return" };
System.Console.WriteLine(b);
}
else if (a == someValue2)
{
string[] b = { "Grab Shovel", "Return" };
System.Console.WriteLine(b);
}
But there's a mistake here: you can't assign something to an array just in curly braces { }, you have to declare it correctly:
string[] arr; // array is not initialized
arr = new string[] { "text", "text", "text" } // the array is now initialized
But that's not really convenient and the code gets bloated, so you should define this variable before the logical construct:
string[] b = new string[] { };
if (a == someValue1)
{
b = new string[] { "Return" };
}
else if (a == someValue2)
{
b = new string[] { "Grab Shovel", "Return" };
}
System.Console.WriteLine(b);
That's more convincing, isn't it?
Now let's think what we can improve here...
The flag variable is of type int, but it takes 0 and 1, which is more like a bool, so let's make it a bool.
Flag can still be made a property to make it easier to use, let's do that!
Let's replace if-else with a switch-case, so there are no unnecessary checks.
And we get the following:
class Program
{
public static bool Flag { get; set; }
public static void Main(string[] args)
{
string[] mainoptions = new string[] { };
Flag = false;
switch (Flag)
{
case true:
mainoptions = new string[] { "Return" };
break;
case false:
mainoptions = new string[] { "Grab Shovel", "Return" };
break;
}
foreach (var option in mainoptions)
System.Console.WriteLine(option);
}
}
Oh, did you also notice that I printed the result differently, and there is a new foreach construct?
foreach (var option in mainoptions)
System.Console.WriteLine(option);
Well, you can't just print the array because you just get its type, not its content. To print the whole array, we have to go through it from index 0 to the end, printing out every value.
You can address the array using the index:
var arr = new int[] { 1, 2, 3, 4 };
Console.WriteLine(arr[0]); // => print 1
Let's make it even cooler, shall we? We use a ternary operator, it's an analogue of if-else when we only have 2 execution paths:
class Program
{
public static bool Flag { get; set; }
public static void Main(string[] args)
{
string[] mainoptions = new string[] { };
Flag = false;
mainoptions = Flag ? new string[] { "Return" } : new string[] { "Grab Shovel", "Return" };
foreach (var option in mainoptions)
System.Console.WriteLine(option);
}
}
I hope this will be useful! Have a nice day!

so what i have learned you can use a If to check a var! you can also use a switch statement witch are super useful!
int Flag = 0;
String mainoptions;
Static void Main()
{
switch(Flag)
{
case 1:
// case means the if this is the var then run this block of code.
// the 1 is the int number so if we put 100 in the place of the 1 then the switch statment would check if the var (Flag) is 100. and if it the code just moves on. you can add whatever you want in the case 1. so if you wanted your string to be "Example" if the int Flag was 1 then you would put:
mainoptions = "mainoption's";
// you can as as many cases as you want as well.
Brake;
}
}
also your mainoptions does not exist bc its a temp var. your int Flag works bc its outside of the method AKA in the class. so in other words you cant use temp vars outside of the method it is put into or initialised in.

Outside of implementing collections yourself, arrays are generally a poor choice for storing a collection of objects. Consider instead using List<string>:
int flag = 0; //Value Changes
var mainOptions = new List<string>{
"Return"
};
if (flag == 0)
{
mainoptions.Insert(0,"Grab Shovel");
}
WriteLine(mainoptions);
(If WriteLine is your own method, you may have to change its signature to accept List<string> instead of string[] and there may be further cascading changes)
Part of what makes arrays awkward to work with is that they have a fixed number of elements. But you're already working in a scenario where you want to easily change the number of elements. So use a type that makes that easy to do.

Related

How to apply arraylist with variables in an Object, inside a method using a for loop in c #

A hw was given to us to change a previous hw in C# which used 2d arrays and instead of using 2d arrays we use an Array list with variables declared in an object called Students.
I would like to use a method to calculate a student best mark; however, the method is giving me an error and a warning which are the following:
Error:
CS0161 'Form1.Calc_HighestMarkOutput(int)': not all code paths return a value.
Warning:
CS0162 Unreachable code detected.
Inside the arraylist the user inputed (through use of an overload constructor):
Student Name, Maths Mark, English Mark, Maltese Mark, Email Address.
and since in the method I am returning 3 highest marks in 3 subjects attained by all students, I decided to return an array. which will be accessed by a temporary array inside the main program by selectedindex.
Please help me find the problem.
And thanks in advance.
public int[] Calc_HighestMarkOutput(int HighestMarkIndex)
{
int[] HighestMarkOutput = new int[3];
int HighestMarkMaths = 0;
int HighestMarkEnglish = 0;
int HighestMarkMaltese = 0;
int TMPHighestMarkMaths = 0;
int TMPHighestMarkEnglish = 0;
int TMPHighestMarkMaltese = 0;
for (int i = 0; i < myStudents.Count; i++) //a loop through an array list.
{
if (myStudents[HighestMarkIndex].Maths_Result > HighestMarkMaths)
{
TMPHighestMarkMaths = myStudents[HighestMarkIndex].Maths_Result;
HighestMarkMaths = TMPHighestMarkMaths;
}
if (myStudents[HighestMarkIndex].English_Result > HighestMarkEnglish)
{
TMPHighestMarkEnglish = myStudents[HighestMarkIndex].English_Result;
HighestMarkEnglish = TMPHighestMarkEnglish;
}
if (myStudents[HighestMarkIndex].Maltese_Result > HighestMarkMaltese)
{
TMPHighestMarkMaltese = myStudents[HighestMarkIndex].Maltese_Result;
HighestMarkMaltese = TMPHighestMarkMaltese;
}
HighestMarkOutput[0] = HighestMarkMaths;
HighestMarkOutput[1] = HighestMarkEnglish;
HighestMarkOutput[2] = HighestMarkMaltese;
return HighestMarkOutput;
}
You are getting an error, because the return-statement is inside the loop. If the list is empty, the return statement will never be executed. Also, you know the result only after the loop has finished. So, place the return-statement after the loop.
Since the purpose of this method is to find the highest marks, it makes no sense to pass such an index into the routine as a parameter.
Using foreach is easier than for because you don't have to deal with indexes.
Instead of returning an array, return an unnamed student containing the results. You can drop useless temporary variables.
public Student Calc_HighestMarkOutput()
{
var result = new Student(); // You also might have to add a default constructor.
foreach (Student student in myStudents) {
if (student.Maths_Result > result.Maths_Result) {
result.Maths_Result = student.Maths_Result;
}
if (student.English_Result > result.English_Result) {
result.English_Result = student.English_Result;
}
if (student.Maltese_Result > result.Maltese_Result) {
result.Maltese_Result = student.Maltese_Result;
}
}
return result;
}
You could also use Math.Max to simplify finding the maximum value
foreach (Student student in myStudents) {
result.Maths_Result = Math.Max(result.Maths_Result, student.Maths_Result);
result.English_Result = Math.Max(result.English_Result, student.English_Result);
result.Maltese_Result = Math.Max(result.Maltese_Result, student.Maltese_Result);
}
With these refactorings, the method shrinks from 22 lines (not counting empty lines and lines containing only a brace) to 7 lines.

How to check next element in the array?

I'm learning and currently trying to write a simple multiple choice quiz. I am not allowed to write it simply with if else statements.
I'm trying to make it so that it asks the question the user inputs the answer (that's all fine) but a separate class works out if it's right or not.
Where my code has the array with a blank index I'm wondering how after the first iteration it would check the next index when that method was called upon again in the next question. I tried to use a for each but then get an error regarding not every path has an outcome.
private static readonly string[] answerArray = new string[5] { "C", "A", "B", "A", "C" };
public static bool AnswerCalc(string ain)
{
if (ain == answerArray[])
{
Console.WriteLine("Correct");
return true;
}
else
{
Console.WriteLine("Sorry that's wrong");
return false;
}
}
I had it as a bool as that's how I was keeping score.
If you want to check if an array contains an item simply:
var aInArr = arr.Contains("A");
This is a LINQ expression built into .net.
One way to implement this as a non-extension method targeting array is like so:
public bool Contains(string[] arr, string inputStr)
{
for(int i = 0; i < arr.Length; i++)
{
if (item == inputStr[i])
return true;
}
return false;
}
Once it runs out of items in the array it will break out of the for loop curly brackets and return false.
Note: for brevity I reduced the result but the .net way to do this is to use an IEnumerable on a generic input instead of an array and use foreach instead of for.
public static Contains<T>(this IEnumerable<T> input, T compared)
{
foreach (var item in input)
{
if (item == compared)
return true;
}
return false;
}
If you store an integer in the class containing this method, you can increment it at the end of the function call (make sure you reset it to 0 when it reaches the length of the array). Use this integer between the square braces like so: if (ain == answerArray[intValue])
If you need more help then let me know and I'll be happy to update this with more information.

Update a variable inside ForEach loop

I simply can't understand why this simple code is not working. My expected output is 10 and 15, but it is returning 2 and 3. That means that the update is not working.
List<int> numbers = new List<int>();
numbers.Add(2);
numbers.Add(3);
numbers.ForEach(n => n = n*5);
numbers.ForEach(n => Console.WriteLine(n));
Note: I've already searched a lot, but I could not understand this behavior.
How should I fix it?
Update: the same behavior for strings.
List<string> strings = new List<string>();
strings.Add("a");
strings.Add("b");
strings.ForEach(s => s = s + "--");
strings.ForEach(s => Console.WriteLine(s));
n is a copy of your current value in the list not a reference to your value.If you want to manipulate the values in your list then use a for loop
for(int i = 0; i<numbers.Count; i++)
numbers[i] *= 5;
More detailed explanation:
With a normal foreach loop your code doesn't even compile:
foreach(var n in numbers)
n = n * 5; // Readonly local variable cannot be used as an assignment target
Remember that List<T>.ForEach loop is not the same as foreach but it is just a method that takes a Action<int> delegate as argument and performs the specified action on the each element in your list.So it performs something like this (taken from the source code):
public void ForEach(Action<T> action)
{
// removed unnecessary parts for brevity
for(int i = 0 ; i < _size; i++)
{
action(_items[i]);
}
}
As you can see here the _item[i] is passed to the action and since int is a value types the copy of your value is passed rather than a reference.And that's why your values didn't change.
For strings: Apart from the fact that strings are immutable, assigning a new reference to a reference type doesn't change the object that holds the same reference.For example consider this:
static void Update(string s)
{
s = "bar";
}
string f = "foo";
Update(f);
Console.WriteLine(f); // foo
Assigning a new reference to s doesn't change the f, f stil holds the old reference and s is pointing to a new location in memory.This is not because s is a copy,it's not.If you change a property of s (with strings you can't do that but try with another reference type), it would update the property of f as well.It works in this way because s and f are two different strings that points to the same location in memory.So s is not bound to f.You can think they were declared like this:
string f = "foo";
string s = f;
s = "bar";
The only exception is when you pass f as a ref argument then the assignment will change the f as well:
static void Update(ref string s)
{
s = "bar";
}
string f = "foo";
Update(ref f);
Console.WriteLine(f); // bar
Because they are value types, rather than mutating the list you could create a modified one using Select
var newList= numbers.Select(n => n = n*5);
As imperative programmers, we love mutating things, which is not a brilliant idea!!
The reason why it did not work for strings is that because by default C# passes a copy of the reference rather than the actual reference.
void Fn(string s)
{
s = "not being changed";
}
Main()
{
var hello = "hello";
Fn(hello);
Console.WriteLine (hello); // prints hello again!!
}
However, if you want to change the reference you have to use the ref keyword.
void Fn(ref string s)
{
s = "Unfortunately, changed!";
}
Main()
{
var hello = "hello";
Fn(ref hello);
Console.WriteLine (hello); // Unfortunately, changed!!!
}
I think that changing parameters' values is a terrible idea and you shouldn't be doing that, you should return a new string that contains the new modifications.
The reason is because the parameter to the ForEach are passed by value and not by reference.
However, if you do pass a reference type, it must work as expected as shown below
class Program
{
static void Main(string[] args)
{
List<Frog> numbers = new List<Frog>();
numbers.Add(new Frog { name = "balcha" });
numbers.Add(new Frog { name = "Tibara" });
numbers.ForEach(n => n.name = "Bontu");
numbers.ForEach(n => Console.WriteLine(n.name));
Console.ReadLine();
}
class Frog
{
public string name { get; set; }
}
}
Output:
Bontu
Bontu

How do I iterate through the contents of an array in C# and still return the entire array afterward?

HOMEWORK: I'm in the middle of designing a hangman game.
I have an array (named wordToGuess[]) representing the word that needs to be guessed. I'm comparing it to a masked copy of that word, (named displayString[] - which I know I still to rename for clarity). If wordToGuess[] is, for instance, [S][T][A][C][K], displayString[] is initialized to [*][*][*][*][*]. As the user guesses a letter, I want to iterate through each character of the array, replacing the * with the letter guess if there's a match. If I guess A (this is the variable letterGuess), for instance, A is compared to every element of the array. If it matches, that element changes to [A]. If it doesn't match, the element remains [*]. The end result in this particular case should be an array populated with [*][*][A][*][*].
public char[] drawProgress(char letterGuess, char[] wordToGuess, char[] displayString)
{
for (int a = 0; a < wordToGuess.Length; a++)
{
if (wordToGuess[a] == letterGuess)
{
displayString[a] = letterGuess;
}
return displayString;
}
}
EDIT:
Here's my problem:
The beginning of the for loop is being flagged as unreachable code and I'm getting an error message that Error 4 'assn5.PromptForLetter.drawProgress(char, char[], char[])': not all code paths return a value.
I'd initially thought it was a scope issue, but commenters explained otherwise....
So...if am in scope with my return, what's causing the errors? what am I missing?
Arrays in .Net are reference types. When you pass a reference type to a function, you get a new variable in the function, but it refers to the same object in memory. What that means here is that you don't have to return anything... the original that you passed to the function will hold the correct value at the end.
What you really want to do is return a boolean, so you know whether or not add to your hangman.
public bool checkProgress(char letterGuess, char[] wordToGuess, char[] displayString)
{
bool result = false;
for (int a = 0; a < wordToGuess.Length; a++)
{
if (wordToGuess[a] == letterGuess)
{
displayString[a] = letterGuess;
result = true;
}
}
return result;
}
.
var word = "hello world".ToCharArray();
var mask = word.Select(c => c==' '?' ':'*').ToArray();
Console.WriteLine(checkProgress('l', word, mask)); // will output "true"
Console.WriteLine(checkProgress('z', word, mask)); // will output "false"
Console.WriteLine(new string(mask)); // will output "**ll* ***l*"
Don't worry if you don't understand some of that syntax: it's just to set up a quick test you can past into the main function of a console project to show that this works.
As a disclaimer, so that you end up with a correct understanding about function argument semantics, I need to remind you again that passing reference types results in a new variable inside the function. What that means is that you when change the variable's properties (including indexes) you are changing the original, but if you assign to the variable itself, you are telling the variable to point to a different object, and the original is no longer affected. Here's a quick example:
public class Foo
{
public string text;
}
public void Test(Foo bar)
{
bar.text = "hello";
bar = new Foo(); //assigned to variable: it now referrs to a different object. original remains unchanged
bar.text = "world";
}
var bar = new Foo();
bar.text= "";
Test(bar);
Console.WriteLine(bar.text); // will output "hello"
This is all turned on it's head if you declare Foo as a struct instead of a class, which would make it a value type. If you were to do that, the output from the sample code would be the original empty string. As another aside, the reasons are academic, but you should never ever design a struct with properties that you can change after construction. Always prefer a class if the type has data that you can mutate.
public char[] drawProgress(char letterGuess, char[] wordToGuess, char[] displayString)
{
for (int a = 0; a < wordToGuess.Length; a++)
{
if (wordToGuess[a] == letterGuess)
{
displayString[a] = letterGuess;
}
}
return displayString;
}
Calling it by:
var output = drawProgress('O', new char[4] { 'S', 'O', 'B', 'O' }, new char[4] { '*', '*', '*', '*'});
output would be {'*', 'O', '*', 'O'}

C# array of variables

Is it possible to do something like this:
string A = "A";
string B = "B";
object[] O = { A, B };
O[0] = "C";
Where A will hold the value "C" in the end?
The code above will replace O[0] with "C", but A remains unchanged.
No - at least not in safe code.
When you create the array, it copies the values into the array. Changing the value in the array later won't change the value of the variable. There's no way of creating a sort of "ref array", where the array elements are shared with the variables. (As shown in Mark's answer, there are sometimes ways of doing this in unsafe code, but I'd really suggest staying away from that.)
Note, however, that if both the array and the variable refer to the same mutable object then mutating that object via either path will make a change which is visible via the other:
StringBuilder x = new StringBuilder();
StringBuilder[] array = new StringBuilder[] { x };
array[0].Append("Foo");
Console.WriteLine(x); // Prints "Foo"
This is no different to any other assignment though - and note that in the code above, the Append call doesn't change the value of either x or the array element; it changes the data within the object that those values refer to.
While the answer is no in the case of string, you can do this with value types:
class Program
{
static unsafe void Main()
{
char A = 'A';
char B = 'B';
var O = new char*[] { &A, &B };
*O[0] = 'C';
System.Console.WriteLine(A + "," + B); // outputs C,B
}
}
Unsafe code is typically frowned upon in C#. So, while this kind of thing is possible, I wouldn't recommend doing it.
What you probably want is to convert your strings into objects with properties.
You can then Cast your array object on the specific key to this object type you created, and then you can set its property again.
This way you can change both what's in your array, as your original variable, therefor, it is similar to seeing it as an array with values by reference.
public class stringObject
{
private string name;
public string Name { get { return name; } set { name = value; } }
}
stringObject A = new stringObject();
A.Name = "A";
stringObject B = new stringObject();
B.Name = "B";
object[] O = { A, B };
//change the array at key 0, and also changing our original variable
stringObject C = O[0] as stringObject;
C.Name = "C";
The above code will not only change what is inside O[0], but it will also update what is inside your object A.
An example with a test to write to the console can be seen here:
https://dotnetfiddle.net/Yt25hy

Categories

Resources