Better way of coding this if statement? - c#

I have another question for you very helpful people. I use a lot of if statements many of which are just repeated and I'm sure could be shortened. This is my current bit of code
if (Globals.TotalStands <= 1)
{
ScoreUpdate.StandNo2.Visible = false;
ScoreUpdate.ScoreStand2.Visible = false;
ScoreUpdate.ScoreOutOf2.Visible = false;
}
if (Globals.TotalStands <= 2)
{
ScoreUpdate.StandNo3.Visible = false;
ScoreUpdate.ScoreStand3.Visible = false;
ScoreUpdate.ScoreOutOf3.Visible = false;
}
if (Globals.TotalStands <= 3)
{
ScoreUpdate.StandNo4.Visible = false;
ScoreUpdate.ScoreStand4.Visible = false;
ScoreUpdate.ScoreOutOf4.Visible = false;
}
if (Globals.TotalStands <= 4)
{
ScoreUpdate.StandNo5.Visible = false;
ScoreUpdate.ScoreStand5.Visible = false;
ScoreUpdate.ScoreOutOf5.Visible = false;
}
if (Globals.TotalStands <= 5)
{
ScoreUpdate.StandNo6.Visible = false;
ScoreUpdate.ScoreStand6.Visible = false;
ScoreUpdate.ScoreOutOf6.Visible = false;
}
if (Globals.TotalStands <= 6)
{
ScoreUpdate.StandNo7.Visible = false;
ScoreUpdate.ScoreStand7.Visible = false;
ScoreUpdate.ScoreOutOf7.Visible = false;
}
if (Globals.TotalStands <= 7)
{
ScoreUpdate.StandNo8.Visible = false;
ScoreUpdate.ScoreStand8.Visible = false;
ScoreUpdate.ScoreOutOf8.Visible = false;
}
as you can see there is a huge amount of code to do something simple (which I do on a few other forms as well and I'm sure there must be a better way of coding this that gets the same result? I'm a code noob so please be gentle, code is C# and software is Visual studio 2008 pro.

Most of your properties should be arrays (or some other collection). For example:
ScoreUpdate.StandNo6
could be this instead:
ScoreUpdate.StandNos[5]
Then you can use a loop instead of all those if statements:
for (int i = 0; i < Globals.TotalStands; ++i)
{
ScoreUpdate.StandNos[i].Visible = true;
ScoreUpdate.ScoreStands[i].Visible = true;
ScoreUpdate.ScoreOutOfs[i].Visible = true;
}
Or this slight variation might be better where there is an array of ScoreUpdates rather than three separate arrays:
for (int i = 0; i < Globals.TotalStands; ++i)
{
var scoreUpdate = ScoreUpdates[i];
scoreUpdate.StandNo.Visible = true;
scoreUpdate.ScoreStand.Visible = true;
scoreUpdate.ScoreOutOf.Visible = true;
}

You should make three arrays or lists of controls and use a loop.

Related

Unique correspondence for characters in C#

I'm new to programming and I got really stuck on an exercise.
I need to determine whether each character in the first string can be uniquely replaced by a character in the second string. Both strings are equal in length.
For example, "aabc ea" and "ddtf hd" , the result needs to be:
True
a => d
b => t
c => f
=>
e => h
If I have for example "abac ea" and "ddtf hd" , the result needs to be:
False
Since "abac ea" and "ddt hd" don't have an unique replacement.
This is my Code:
using System;
namespace UniqueStrings
{
class Program
{
static void Main(string[] args)
{
string firstPhrase = Console.ReadLine();
string secondPhrase = Console.ReadLine();
bool result = false;
int charsCount = 0;
char[] firstPhraseChars = new char[firstPhrase.Length];
char[] secondPhraseChars = new char[secondPhrase.Length];
if (firstPhrase.Length != secondPhrase.Length)
{
result = false;
}
for (int i = 0; i < firstPhrase.Length; i++)
{
if (firstPhrase[i] == firstPhraseChars[i])
{
firstPhraseChars[i] = firstPhrase[i];
secondPhraseChars[i] = secondPhrase[i];
}
for (int j = 0; j < secondPhrase.Length; j++)
{
if (secondPhrase[j] == secondPhraseChars[j])
{
firstPhraseChars[j] = firstPhrase[j];
secondPhraseChars[j] = secondPhrase[j];
result = false;
}
else
{
result = true;
}
}
}
for (int i = 0; i < firstPhrase.Length; i++)
{
if (result == false)
{
firstPhraseChars[charsCount] = firstPhrase[i];
secondPhraseChars[charsCount] = secondPhrase[i];
charsCount++;
}
}
if (result == false)
Console.WriteLine(result);
else
{
Console.WriteLine(result);
for (int i = 0; i < firstPhrase.Length; i++)
{
Console.WriteLine(firstPhrase[i] + " => " + secondPhrase[i]);
}
}
Console.Read();
}
}
}
Can someone please help me understand what I'm doing wrong? I have no idea anymore and I feel like this code will never work. There needs to be some solution to this, which I'm not understanding.
I'm not supposed to use LINQ, list or dictionary, only System.
If anyone has other questions, feel free to ask.
exemple of non-optimized solution
using System;
namespace UniqueStrings
{
class Program
{
static bool CheckStringSimilarity(string firstPhrase, string secondPhrase)
{
if (firstPhrase.Length != secondPhrase.Length)
{
return false;
}
var length = firstPhrase.Length;
for (var i =0; i<length; i++)
{
for(var j=0; j<length; j++ )
{
if((firstPhrase[i] == firstPhrase[j]) && (secondPhrase[i] != secondPhrase[j]))
{
return false;
}
if((firstPhrase[i] != firstPhrase[j]) && (secondPhrase[i] == secondPhrase[j]))
{
return false;
}
}
}
return true;
}
static void Main(string[] args)
{
Console.WriteLine($"CheckStringSimilarity('aaa','bbb') = {CheckStringSimilarity("aaa", "bbb")}");
Console.WriteLine($"CheckStringSimilarity('aaab','bbbc') = {CheckStringSimilarity("aaab", "bbbc")}");
Console.WriteLine($"CheckStringSimilarity('rrt','aze') = {CheckStringSimilarity("rrt", "aze")}");
Console.WriteLine($"CheckStringSimilarity('rrt dd','aad aa') = {CheckStringSimilarity("rrt dd", "aad aa")}");
}
}
}
DEMO
In your first for loop the result will always be true since both if statements will always return false. When the if statements compare their values "firstPhraseChars[i]" and "secondPhraseChars[j]" are always empty since you never put anything into these arrays before the comparison.
Hope this helps without giving away too much ;)
You can look for a counter example: if you've found it, correspondent doesn't exist:
private static bool HasCorrespondence(string left, string right) {
if (left == null)
return right == null;
if (right == null)
return false;
if (left.Length != right.Length)
return false;
// known correspondence
Dictionary<char, char> correspondence = new Dictionary<char, char>();
for (int i = 0; i < left.Length; ++i)
if (correspondence.TryGetValue(left[i], out char expected)) {
// counter example: we want expected, but have right[i]
if (expected != right[i])
return false;
}
else
// we have nothing for left[i], so we can add (left[i], right[i]) pair
correspondence.Add(left[i], right[i]);
// no counter example exists, return true
return true;
}
If Dictionary is prohibited, you can emulate it with help of array:
private static bool HasCorrespondence(string left, string right) {
if (left == null)
return right == null;
if (right == null)
return false;
if (left.Length != right.Length)
return false;
int[] correspondence = new int[char.MaxValue];
for (int i = 0; i < left.Length; ++i)
if (correspondence[left[i]] != 0) {
if (correspondence[left[i]] != right[i])
return false;
}
else
correspondence[left[i]] = right[i];
return true;
}
If you are looking for one to one correspondence, you can just check twice"
private static bool HasOneToOne(string left, string right) =>
HasCorrespondence(left, right) &&
HasCorrespondence(right, left);

Shift selection c# optimization

Basically I have done a code which works as a shift selection, I have already programmed the file selection working with Ctrl-Key selection, but it is required to optimize it. Nevertheless I have not found any way to make it easier has anyone any idea of how could I achieve that? The highlightedIndex is a list of int.
private int lastClickedPointIdx = -1;
int firstvaluepoint = 0;
private int movingPointIdx = -1; //-1: no point moving
private void KeySelection()
{
bool shiftclick = false;
int firstselectedpoint = 0;
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) //Ctrl
{
if (highlightedIndex.Contains(movingPointIdx)) //remove point if already is in the highlightedIndex list
{
highlightedIndex.Remove(movingPointIdx);
firstselectedpoint = movingPointIdx;
shiftclick = false;
return;
}
else //otherwise add it to the highlightedIndex list
{
highlightedIndex.Add(movingPointIdx);
highlightedIndex.Sort();
firstselectedpoint = movingPointIdx;
shiftclick = false;
}
}
else if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) //Shift
{
if (!shiftclick)
{
highlightedIndex.Clear();
shiftclick = true;
}
if (lastClickedPointIdx > -1) //highlights all points
{
if (firstvaluepoint > firstselectedpoint)
{
for (int i = firstselectedpoint; i <= firstvaluepoint; i++)
{
highlightedIndex.Add(i);
}
}
else
{
for (int i = firstvaluepoint; i <= firstselectedpoint; i++)
{
highlightedIndex.Add(i);
}
}
}
}
lastClickedPointIdx = movingPointIdx;
if (!shiftclick)
firstvaluepoint = firstselectedpoint;
}

Referencing components of objects from an array in C#

I'm trying to make a "thing" that checks/unchecks a specific object's interactable checkbox from an array by using player pref integers. The problem I'm having is I can't seem to reference specific objects from an array, please help.
Here's some script:
//This part is from the Start function.
for (int i = 0; i < buttons.Length; i++) {
if (PlayerPrefs.GetInt("button" + i) == null) {
PlayerPrefs.SetInt("button" + i, 1);
}
if (PlayerPrefs.GetInt("button" + i) == 1) {
button.interactable = true;
} else {
button.interactable = false;
}
}
void Update () {
for (int i = 0; i < buttons.Length; i++) {
if (PlayerPrefs.GetInt("button" + i) == 0) {
button.interactable = false;
}
}
}
The areas where you can see button.interactable = true/false are where I'm having problems.
If you don't have button defined somewhere else; I assume you are missing the concept of array index accessors; you might want to use buttons[i] instead of button.

How I can search keyword from text file/ sql file in c#.net which are not commented?

I have to search keywords from a .sql or .txt file. Those keywords should not be in comments.
e.g. if I want to search 2 keywords like "set rowcount" and "holdlock". I was able to find these in a file. But As per requirement. these should not be in comment. (not between /* */ or starts with //).
Can anyone give me an idea.
foreach (string word in words)
{
int s_start = FileDisplayArea.SelectionStart, startIndex = 0, index;
int wordIndex = 0;
while ((index = FileDisplayArea.Text.IndexOf(word, startIndex)) != -1)
{
NoOfOccurance[wordIndex] += 1;
FileDisplayArea.Select(index, word.Length);
FileDisplayArea.SelectionColor = Color.Yellow;
startIndex = index + word.Length;
}
FileDisplayArea.SelectionStart = s_start;
FileDisplayArea.SelectionLength = 0;
FileDisplayArea.SelectionColor = Color.Red;
wordIndex += 1;
}
Thanks for help guys. I solved this by following logic.
bool commentStarted = false, commentEnds = false;
foreach (string line in scriptAllLines)
{
if (line.Contains("/*"))
{
commentStarted = true;
commentEnds = false;
}
if (line.Contains("*/"))
{
commentEnds = true;
commentStarted = false;
}
}

Simplify Complicated If statements

Well, I have a Form that receives the Employee's level and enable some options depending on his level using a bunch of Checkboxes. However the problem i am facing is that for my application's logic there is specific level range for every option to be enabled so i created an Ugly IF range checking statements that i am sure there is a better way to achieve.
CODE:
if (level >= 1 && level < 3) {
_items[0].Enabled = true;
_items[1].Enabled = false;
_items[2].Enabled = false;
_items[3].Enabled = false;
_items[4].Enabled = false;
_items[5].Enabled = false;
_items[6].Enabled = false;
_items[7].Enabled = false;
}
else if (level >= 3 && level < 5) {
_items[0].Enabled = true;
_items[1].Enabled = true;
_items[2].Enabled = false;
_items[3].Enabled = false;
_items[4].Enabled = false;
_items[5].Enabled = false;
_items[6].Enabled = false;
_items[7].Enabled = false;
}
else if (level >= 5 && level < 7) {
_items[0].Enabled = true;
_items[1].Enabled = true;
_items[2].Enabled = true;
_items[3].Enabled = false;
_items[4].Enabled = false;
_items[5].Enabled = false;
_items[6].Enabled = false;
_items[7].Enabled = false;
}
else if (level >= 7 && level < 9) {
_items[0].Enabled = true;
_items[1].Enabled = true;
_items[2].Enabled = true;
_items[3].Enabled = true;
_items[4].Enabled = false;
_items[5].Enabled = false;
_items[6].Enabled = false;
_items[7].Enabled = false;
}
else if (level >= 9 && level < 11) {
_items[0].Enabled = true;
_items[1].Enabled = true;
_items[2].Enabled = true;
_items[3].Enabled = true;
_items[4].Enabled = true;
_items[5].Enabled = false;
_items[6].Enabled = false;
_items[7].Enabled = false;
}
else if (level >= 11 && level < 13) {
_items[0].Enabled = true;
_items[1].Enabled = true;
_items[2].Enabled = true;
_items[3].Enabled = true;
_items[4].Enabled = true;
_items[5].Enabled = true;
_items[6].Enabled = false;
_items[7].Enabled = false;
}
else if (level >= 13 && level < 15) {
_items[0].Enabled = true;
_items[1].Enabled = true;
_items[2].Enabled = true;
_items[3].Enabled = true;
_items[4].Enabled = true;
_items[5].Enabled = true;
_items[6].Enabled = true;
_items[7].Enabled = false;
}
else if (level >= 15 && level < 17) {
_items[0].Enabled = true;
_items[1].Enabled = true;
_items[2].Enabled = true;
_items[3].Enabled = true;
_items[4].Enabled = true;
_items[5].Enabled = true;
_items[6].Enabled = true;
_items[7].Enabled = true;
}
You can simplify this with a little math:
int on = (level+1)/2;
for (int i = 0 ; i != 8 ; i++) {
_items[i].Enabled = (i < on);
}
The first line converts a number in the range from 1 to 16, inclusive, to a number in the range from 1 to 8, inclusive. Then the loop goes through all items, and enables as many of them as is indicated by the value of the on variable computed earlier.
You (might) lose performance, but its arguably more readable. Choose your poison! The performance difference depends on how often this is called.
if(level >= 1) {
_items[0].Enabled = level >= 1;
_items[1].Enabled = level >= 3;
_items[2].Enabled = level >= 5;
_items[3].Enabled = level >= 8;
_items[4].Enabled = level >= 9;
_items[5].Enabled = level >= 11;
_items[6].Enabled = level >= 13;
_items[7].Enabled = level >= 15;
}
One option, you could use a Dictionary to store the range for each checkbox-index:
private static Dictionary<int, Tuple<int, int>> _Ranges = new Dictionary<int, Tuple<int, int>>()
{
{ 0, Tuple.Create(1, 3) },{ 1, Tuple.Create(3, 5) },{ 2, Tuple.Create(5, 7) },{ 3, Tuple.Create(7, 9) },
{ 4, Tuple.Create(9, 11) },{ 5, Tuple.Create(11, 13) },{ 6, Tuple.Create(13, 15) },{ 7, Tuple.Create(15, 17) }
};
Now this concise code should do the same:
for(int i = 0; i <= 7; i++)
{
var range = _Ranges[i];
_items[i].Enabled = level >= range.Item1 && level < range.Item2;
}
You could also create a custom Range class which encapsulates this logic.
Turn it around to something like this instead:
_items[0].Enabled = ( level >= 1 && level < 17 );
....
Get rid of the elses:
_items[0].Enabled = false;
_items[1].Enabled = false;
_items[2].Enabled = false;
_items[3].Enabled = false;
_items[4].Enabled = false;
_items[5].Enabled = false;
_items[6].Enabled = false;
_items[7].Enabled = false;
if (level >= 1)
_items[0].Enabled = true;
if (level >= 3)
_items[1].Enabled = true;
if (level >= 5)
_items[2].Enabled = true;
if (level >= 7)
_items[3].Enabled = true;
if (level >= 9)
_items[4].Enabled = true;
if (level >= 11)
_items[5].Enabled = true;
if (level >= 13)
_items[6].Enabled = true;
if (level >= 15 && level < 17)
_items[7].Enabled = true;
Your security levels seem to be perfectly overlapping
So could you not do something as simple as
_items[0].Enabled = (level >= 1);
_items[1].Enabled = (level >= 3);
_items[2].Enabled = (level >= 5);
etc?
I would tend to suggest that this method of enabling / disabling the form components is flawed to begin with. And the top answer only solves this narrow case, where the items in the form are ordered and correspond 1 to N with the privilege levels...
If this application uses any kind of presentation separation scenario (MVC, MVVM, etc.) then this should certainly be done differently through databinding.
But even in the most naive case, a better way to handle this would be to add a privilege level flag to the checkboxes (maybe using their Tag in WinForms, an attached property in WPF, etc.) and loop through them comparing against the current privilege of the user. A dictionary of checkbox to privilege level would also work nicely:
Dictionary<Control, int> RequiredControlPrivilege;
foreach(var item in _items)
{
if(RequiredControlPrivilege.Contains(item)
{
item.Enabled = RequiredControlPrivilege[item] >= CurrentLevel
}
else
{
item.Enabled = false //Default to false or change to true...
}
}

Categories