comparing strings, one from an array other from an entered value - c#

Basically comparing a string that is entered, and trying to get that position from the array.
If I initialize position to 0 then it returns the position zero of the array, if I initialize to 1 then it gives me the item in slot 1, so it's skipping the compare statement.
I also tried using (custStatus == cardStatus[i])
public static int discount(string []cardStatus, int []pDiscount, string custStatus)
{
int position= 0;
int discount;
for(int i = 0; i < 2; i++)
{
if (string.Equals(custStatus, cardStatus[i]))
position = i;
}
discount = pDiscount[position];
return discount;
}

With your code, there's no way to tell if position = 0 means custStatus was found in your cardStatus array or if no match was made at all and the default value is being used. I'd recommend either using a boolean matchFound variable or setting position = -1 and adding an extra if statement at the end either way. Either:
boolean matchFound = false;
...
if(matchFound)
{
discount = pDiscount[position];
}
or else
int position = -1;
...
if(position >= 0)
{
discount = pDiscount[position];
}

Give this a try:
public static int discount(string[] cardStatus, int[] pDiscount, string custStatus) {
var position = Array.IndexOf(cardStatus, custStatus);
return (position == -1) ? -1 : pDiscount[position];
}

public static int discount(string []cardStatus, int []pDiscount, string custStatus)
{
for(int i = 0; i < Math.Min(cardStatus.Length, pDiscount.Length); i++)
{
if (string.Equals(custStatus, cardStatus[i]))
{
return pDiscount[i];
}
}
return -1;
}
Don't be afraid to return directly from FOR-loop, it is old-school that teaches to have only one return point from method. You can have as many returns as it helps you to keep your code clean and easy to read.
And perhaps it would be better to use the following expression in for-loop as it will guard you from possible different lengths of arrays:
for (int i = 0; i < Math.Min(cardStatus.Length, pDiscount.Length; i++)

This looks ok, even though this is somewhat more straightforward:
for(int i = 0; i < cardStatus.Length; i++)
{
if (custStatus == cardStatus[i])
{
position = i;
break;
}
}
Given your question it appears to be the case that all cardStatus[i] match custStatus - did you check the input?
Also given your code what happens if there is no match? Currently you would return pDiscount[0] - that doesn't seem to be correct.

Related

Nearest value from user input in an array C#

so in my application , I read some files into it and ask the user for a number , in these files there a lot of numbers and I am trying to find the nearest value when the number they enter is not in the file. So far I have as following
static int nearest(int close_num, int[] a)
{
foreach (int bob in a)
{
if ((close_num -= bob) <= 0)
return bob;
}
return -1;
}
Console.WriteLine("Enter a number to find out if is in the selected Net File: ");
int i3 = Convert.ToInt32(Console.ReadLine());
bool checker = false;
//Single nearest = 0;
//linear search#1
for (int i = 0; i < a.Length; i++)//looping through array
{
if(a[i] == i3)//checking to see the value is found in the array
{
Console.WriteLine("Value found and the position of it in the descending value of the selected Net File is: " + a[i]);
checker = true;
}
else
{
int found = nearest(i3,a);
Console.WriteLine("Cannot find this number in the Net File however here the closest number to that: " + found );
//Console.WriteLine("Cannot find this number in the Net File however here the closest number to that : " + nearest);
}
}
When a value that is in the file is entered the output is fine , but when it comes to the nearest value I cannot figure a way. I can't use this such as BinarySearchArray for this. a = the array whilst i3 is the value the user has entered. Would a binary search algorithm just be simpler for this?
Any help would be appreciated.
You need to make a pass over all the elements of the array, comparing each one in turn to find the smallest difference. At the same time, keep a note of the current nearest value.
There are many ways to do this; here's a fairly simple one:
static int nearest(int close_num, int[] a)
{
int result = -1;
long smallestDelta = long.MaxValue;
foreach (int bob in a)
{
long delta = (bob > close_num) ? (bob - close_num) : (close_num - bob);
if (delta < smallestDelta)
{
smallestDelta = delta;
result = bob;
}
}
return result;
}
Note that delta is calculated so that it is the absolute value of the difference.
Well, first we should define, what is nearest. Assuming that,
int nearest for given int number is the item of int[] a such that Math.Abs(nearest - number) is the smallest possible value
we can put it as
static int nearest(int number, int[] a)
{
long diff = -1;
int result = 0;
foreach (int item in a)
{
// actual = Math.Abs((long)item - number);
long actual = (long)item - number;
if (actual < 0)
actual = -actual;
// if item is the very first value or better than result
if (diff < 0 || actual < diff) {
result = item;
diff = actual;
}
}
return result;
}
The only tricky part is long for diff: it may appear that item - number exceeds int range (and will either have IntegerOverflow exceprion thrown or *invalid answer), e.g.
int[] a = new int[] {int.MaxValue, int.MaxValue - 1};
Console.Write(nearest(int.MinValue, a));
Note, that expected result is 2147483646, not 2147483647
what about LINQ ?
var nearestNumber = a.OrderBy(x => Math.Abs(x - i3)).First();
Just iterate through massive and find the minimal delta between close_num and array members
static int nearest(int close_num, int[] a)
{
// initialize as big number, 1000 just an example
int min_delta=1000;
int result=-1;
foreach (int bob in a)
{
if (Math.Abs(bob-close_num) <= min_delta)
{
min_delta = bob-close_num;
result = bob;
}
}
return result;
}

How to fix the output after I compare two arrays in C#?

So I have this homework assignment that requires me to assign output to labels after I compare two arrays. My problem is that after I compare the two arrays, the output I assign is wrong. I'm supposed to out 'Y' if at a specific index of the two arrays are equal and 'N' if they're not equal but every time I run the code, it outputs 'Y' to all the labels no matter what. How can I fix what is being outputted after the comparison?
private void evaluateStudentAnswers()
{
/* Use a "for" loop to cycle through the answerKey[] and studentAnswers[] arrays, and compare the answers
* in the two arrays at each index. If they match, then increment the global variable "correctAnswers"
* and assign the value 'Y' to the corresponding index in the correctOrIncorrect[] array. if they
* don't match, then increment the global variable "incorrectAnswers" and assign the value 'N' to the
* corresponding indes in the correctOrIncorrec[] array. These two variables will be used to calculate
* the grade percentage.
*/
for (int i = 0; i < studentAnswers.Length; i++)
{
for(int j = 0; j < answerKey.Length; j++)
{
// I think the indexes below are being checked if they're the same and I need to make sure not just the
//indexes are the same but the values as well
if (studentAnswers[i] == answerKey[j])
{
correctAnswers++;
for(int k = 0; k < correctOrIncorrect.Length; k++)
{
correctOrIncorrect[k] = 'Y';
}
}
else
{
incorrectAnswers++;
for (int k = 0; k < correctOrIncorrect.Length; k++)
{
correctOrIncorrect[k] = 'N';
}
}
}
}
}
I think your code can be simplified quite a lot. assuming there's a 1-1 mapping between studentAnswers and answerKey.
for (int i = 0; i < studentAnswers.Length; i++)
{
var studentAnswer = studentAnswers[i];
var answer = answerKey[i];
if (studentAnswer == answer)
{
++correctAnswers;
correctOrIncorrect[i] = 'Y';
}
else
{
++incorrectAnswers;
correctOrIncorrect[i] = 'N'
}
}
All of the arrays are the same size. So when we loop over each answer the student provided, we know we can find the corresponding correct answer in answerKey. Also, the tracking of correct answers also follows the same pattern, for each studentAnswer, we want to record the correctness in correctOrIncorrect, which corresponds to the particular answer the student provided. As such, we only need to perform a single loop, since the i refers to the appropriate index in all the arrays as we're processing.
If studentAnswers.Length == answerKey.Length == correctOrIncorrect.Length
Then
for (int i = 0; i < studentAnswers.Length; i++)
{
if(studentAnswers[i] == answerKey[j])
{
correctAnswers++;
correctOrIncorrect[k] = 'Y';
}
else
{
incorrectAnswers++;
correctOrIncorrect[k] = 'N';
}
}
Since it is an assignment I wont give an answer :) but since you are stuck I encourage you use the guidance below.
These two are unnecessary in your code
inner for-loop on correctOrIncorrect[]
variable "k", you can use "i" instead for correctOrIncorrect value assignment
Since the arrays have to have the same size/order, you only need to loop through them once. Also I find ternary assignments more clear than if blocks:
Func<bool, int> toInt = (b) => b ? 1 : 0;
for (int i = 0; i < studentAnswers.Length; i++)
{
var studentAnswer = studentAnswers[i];
var answer = answerKey[i];
var isCorrect = studentAnswer == answer;
correctOrIncorrect[i] = isCorrect ? 'Y' : 'N';
correctAnswers = isCorrect ? 1 : 0; // toInt(isCorrect)
incorrectAnswers = !isCorrect ? 1 : 0; // toInt(!isCorrect)
}
}
Or in LINQ (just because it's worth learning, but probably not appropriate for homework):
correctOrIncorrect = answerKey.Zip(studentAnswer, (a,b) => a == b ? "Y" : "N").ToArray();
incorrectAnswers = correctOrIncorrect.Count(x => x == "Y");
...

How to change this function to the recursive function

I have the following code that compares the node.Texto each both given node sets and then return one if they are equal otherwise zero. But my problem is that it just compare the first children because of nodes2.Nodes[ii] hence I know that it will not go forward more.
As I know if it was TreeNodeCollection it was easy to do recursive for each node and sub-node using foreach loop.
But here how I could change the code to the recursive version?
thanks in advance!
public int Compare_ChildNodes(TreeNode nodes1, TreeNode nodes2)
{
int length_children1 = nodes1.Nodes.Count;
int length_children2 = nodes2.Nodes.Count;
int result_int = 1;
if (length_children1 != length_children2)
{
result_int = 0;
}
else
{
for (int ii = 0; ii < length_children1; ii++)
{
if (nodes1.Nodes[ii].Text.Equals(nodes2.Nodes[ii].Text))
{
int ret = Compare_ChildNodes(nodes1.Nodes[ii], nodes2.Nodes[ii]);
result_int = ret;
}
else
{
result_int = 0;
}
}
}
return result_int;
}
I can't see any problems here. Calling Compare_ChildNodes with nodes1.Nodes[ii] and nodes2.Nodes[ii] does exactly the recursion you want.
I'd just suggest a little optimization ("early out") for your code:
public int Compare_ChildNodes(TreeNode nodes1, TreeNode nodes2)
{
int length_children1 = nodes1.Nodes.Count;
int length_children2 = nodes2.Nodes.Count;
int result_int = 1;
if (!nodes1.Text.Equals(nodes2.Text)) return 0; // not equal
if (length_children1 != length_children2) return 0; // not equal
return nodes1.Nodes.OfType<TreeNode>.Select((node, idx) =>
Compare_ChildNodes(node, nodes2.Nodes[idx]).Any(result => result == 0) ? 0 : 1;
}
I changed the comparison for the node's text to another recursion level so you can recurse using linq.
The linq Any method checks if any of the comparisons (in the Select method) returns 0 indicating that a child node collection is not equal.
The Select is called for each TreeNode in node1.Nodes and with it's index in that collection. So you can use this index to get the matching node from node2.Nodes and call Compare_ChildNodes for these two.
As soon as you find unequal (child-)nodes, you can return 0 and don't need to continue comparing the other nodes.
If you cannot use the linq statements (for Framework reasons or others), you can still use your for loop:
for (int idx = 0; idx < length_children1; idx++)
if (Compare_ChildNodes(nodes1.Nodes[idx], nodes2.Nodes[idx]) == 0)
return 0;
return 1;

c# string split and combine

i have a string that conatin 5 numbers like
'1,4,14,32,47'
i want to make from this string 5 strings of 4 number in each one
like :
'1,4,14,32'
'1,4,14,47'
'1,4,32,47'
'1,14,32,47'
'4,14,32,47'
what is the simple/faster way to do it
is the way of convert this to array unset every time diffrent entery and combine
them back to string ?
is there a simple way to do it ?
thanks
How about something like
string s = "1,4,14,32,47";
string r = String.Join(",", s.Split(',').Where((x, index) => index != 1).ToArray());
Using string.Split() you can create a string array. Loop through it, so that in each loop iteration you indicate which element should be skipped (on the first pass, ignore the first element, on the second pass, ignore the second element).
Inside that loop, create a new array that contains all elements but the one you want to skip, then use string.Join() to create each result.
Have a look at:
http://msdn.microsoft.com/en-us/magazine/ee310028.aspx Here you'll find an example in F# who will give the correct background in combinations and permutations (that's how is called what you need). There is code too, I think it's easy to translate it in C#
Example of Code in C# (text in Italian but code in English)
For those who need a more generic algorithm, here is one which gives n length subsets of m items:
private void GetPermutations()
{
int permutationLength = 4;
string s = "1,4,14,32,47";
string[] subS = s.Split(',');
int[] indexS = new int[permutationLength];
List<string> result = new List<string>();
IterateNextPerm(permutationLength, indexS, subS, result);
// Result will hold all your genberated data.
}
private void IterateNextPerm(int permutationLength, int[] pIndexes, string[] subS, List<string> result)
{
int maxIndexValue = subS.Count() - 1;
bool isCorrect = true;
for (int index = 0; index < permutationLength - 1; index++)
{
if (pIndexes[index] >= pIndexes[index + 1])
{
isCorrect = false;
break;
}
}
// Print result if correct
if (isCorrect)
{
string strNewPermutation = string.Empty;
for (int index = 0; index < permutationLength; index++)
{
strNewPermutation += subS[pIndexes[index]] + ",";
}
result.Add(strNewPermutation.TrimEnd(','));
}
// Increase last index position
pIndexes[permutationLength - 1]++;
// Check and fix if it's out of bounds
if (pIndexes[permutationLength - 1] > maxIndexValue)
{
int? lastIndexIncreased = null;
// Step backwards and increase indexes
for (int index = permutationLength - 1; index > 0; index--)
{
if (pIndexes[index] > maxIndexValue)
{
pIndexes[index - 1]++;
lastIndexIncreased = index - 1;
}
}
// Normalize indexes array, to prevent unnecessary steps
if (lastIndexIncreased != null)
{
for (int index = (int)lastIndexIncreased + 1; index <= permutationLength - 1; index++)
{
if (pIndexes[index - 1] + 1 <= maxIndexValue)
{
pIndexes[index] = pIndexes[index - 1] + 1;
}
else
{
pIndexes[index] = maxIndexValue;
}
}
}
}
if (pIndexes[0] < maxIndexValue)
{
IterateNextPerm(permutationLength, pIndexes, subS, result);
}
}
I know that it's not the nicest coding, but I've written it right now in the last half an hour so I'm sure there are things to tweek there.
Have fun coding!
var elements = string.Split(',');
var result =
Enumerable.Range(0,elements.Length)
.Reverse()
.Select(
i=>
string.Join(","
Enumerable.Range(0,i).Concat(Enumerable.Range(i+1,elements.Length - i - 1))
.Select(j=>elements[j]).ToArray() // This .ToArray() is not needed in NET 4
)
).ToArray();
your wording is pretty confusing...but the example is clear enough. just split it on commas, then remove one index, then use string.Join(",", list); to put it back together..

Infinite Loop? Can't see why

I have a function that takes in a roleID(as an int), and compares it to a multidimensional array to see if that array contains that roleID. if it does, it sets a bool to true and breaks. if it doesn't, the loop never exits. I'm hoping this is something stupid that I'm overlooking, but I've had a few different people look it over now.
The size of the userRoles array that I am testing with right now is 3. I can print userRoles.GetLength(0) and it says 3, and that matches whats in the database.
here's the code:
public bool IsInRole(int roleID)
{
bool inRole = false;
int i = userRoles.GetLength(0);
for (int j = 0; j < i; j++)
{
if (Convert.ToInt32(userRoles[j, 0]) == roleID)
{
inRole = true;
break;
}
}
return inRole;
}
TIA,
Chris
Are you sure that you're not misdiagnosing the symptom, and that it really is getting stuck in the loop? The code you have there doesn't look like wrong, my first thought would be that the place that you're calling IsInRole() isn't handling a 'false' return correctly.
Is j actually incrementing? or is it somehow being reset it back to 0?
Try this
public bool IsInRole(int roleID)
{
bool inRole = false;
int i = userRoles.GetLength(0);
for (int j = 0; j < i; j++)
{
int k = j;
if (Convert.ToInt32(userRoles[k, 0]) == roleID)
{
inRole = true;
break;
}
}
return inRole;
}
Looking at MSDN's GetLength property, to quote 'An example of GetLength is GetLength(0), which returns the number of elements in the first dimension of the Array.'
public bool IsInRole(int roleID)
{
bool inRole = false;
try{
int i = userRoles.GetLength(0);
for (int j = 0; j < i; j++)
{
if (Convert.ToInt32(userRoles[j, 0]) == roleID)
{
inRole = true;
break;
}
}
}catch(Exception up){
throw up;
}
return inRole;
}
I would be inclined to wrap the logic into a try/catch to see if the Convert.ToInt32 or GetLength(0) is throwing an exception...
Hope this helps,
Best regards,
Tom.
Your loop looks solid so it must be not exiting for a different reason. Could your array contain a value that would cause Convert.ToInt32 to hang or throw?

Categories

Resources