C#: Choosing operator depending on boolean value (in one line) - c#

I'm trying to get away with a slick one liner as I feel it is probably possible.
I'll put my code below and then try to explain a little more what I'm trying to achieve.
for (int p = 0; p < 2; p++)
{
foreach (string player in players[p])
{
if (PlayerSkills[player].streak_count *>* 0) //This line
PlayerSkills[player].streak_count++;
else
PlayerSkills[player].streak_count = 0;
}
}
*(p==0 ? >:<) the comparison operator is chosen depending on p.
Of course what I've written is rubbish. But basically I want to use >0 when p==0, and <0 when p>>0. Is there a nice way to achieve this?

Well, you should use what is most readable, even if it is not as consice. That said...
// Invert the count for all but the first player and check for a positive number
if (PlayerSkills[player].streak_count * (p==0 ? 1 : -1) > 0)

I don't know about slick, but the following and/or combination is one line:
if ((p == 0 && PlayerSkills[player].streak_count > 0)
|| PlayerSkills[player].streak_count < 0)
...
This will only ever do the array index once (due to the p==0 condition occurring first) and so is equivalent to the "ternary" you wrote (albeit a bit more verbose).

p > 0 ? whenGreaterThanZero : whenZeroOrLess ;
E.g.
int p = 1; bool test = p > 0 ? true : false ;
Lets test = True

Related

if statement with multiple conditions instead of using AND

I been searching for some information about if statements with multiple conditions but haven't found something that corresponds to myquestion.
I was wondering if you could write:
int n = 3
if (3 < n < 20)
{
//do something..
}
rather than doing:
if (n > 3 && n < 20)
{
//do something..
}
The first statement doesn't work for me which i think it should, because it's plain simple.
Maybe someone can give me the correct syntax for doing so or maybe it's just impossible at all and i just have to go with the AND.
To explain why it's invalid:
if (3 < n < 20)
Could be rewritten as:
if ((3 < n) < 20)
Now 3 < n's outcome would be a bool.
So basically you'll get:
if (true/false < 20)
Which is not valid in C#.
Stefan's answer explains why it's impossible.
But here is a workaround, if you don't want to write that pesky && explicit conditions every time - you can create an extension method:
public static class IComparableExtensions
{
public static bool Between<T>(this T self, T low, T high) where T : IComparable
{
return self.CompareTo(low) > 0 && self.CompareTo(high) < 0;
}
}
And use it like this:
int n = 5;
if(n.Between(3, 20))
{
// do your stuff here
}
Please note, however, that this might be confusing - since Between doesn't specify if the compare is inclusive, exclusive, or inclusive in only one direction - so if you compare, say, 20.Between(10, 20) - should it return true or false?
A better approach would require adding another variable to the method, to indicate that:
[Flags]
public enum CompareMode
{
Exclusive = 0,
IncludeLow = 1,
IncludeHigh = 2,
Inclusive = IncludeLow | IncludeHigh
}
public static class IComparableExtensions
{
public static bool Between<T>(this T self, T low, T high, CompareMode mode) where T : IComparable
{
var compareLow = (mode & CompareMode.IncludeLow) == CompareMode.IncludeLow ? 0 : 1;
var compareHigh = (mode & CompareMode.IncludeHigh) == CompareMode.IncludeHigh ? 0 : -1;
return self.CompareTo(low) >= compareLow && self.CompareTo(high) <= compareHigh;
}
}
Now you use it like this:
if(n.Between(3, 20, CompareMode.Exclusive))
{
// do your stuff here
}
You can see a live demo on rextester.
This way, another person reading this code (or even you, 6 months from now) will know immediately, without having to look inside the Between extension method, if between is inclusive, exclusive, or whatever.
Generally it is not possible what you want to do.
but in your logic if you want to perform single liner logic you can use ternary operator.
for eg. you need to assign value of n to variblae result else it should be 0 as default.
int result = n > 3 ? (n < 20 ? n : 0) : 0
it is equivalent to
int result = 0;
if (n > 3 && n < 20)
{
result = n;
}

C# Validation for specific input

I'm kinda new to this thread, but in short summary i'm having trouble with a small validation issue. Basically, i'm attempting to make a simple validation program that will collect a user's input and then determine if the input is valid in terms of, input being correctly implemented, the number being positive, and the number having to be either 0, 1, 2, 3, 4 or 5.
The overall program runs, but the issue i'm facing is every form of input is deemed an error, thus displaying my error statement, even if it is a valid input like 5 for example. I feel like there is a small mistake,i have made that is causing this, So is there any suggestions?
int user_input;
int count = 0;
do
{
Console.Write("\n\nUser Input:"
if ((int.TryParse(Console.ReadLine(), out user_input) == false)||(user_input < 0 || user_input != 0 ||user_input != 1 || user_input != 2
|| user_input != 3 || user_input != 4 || user_input != 5))
{
Console.WriteLine("Error : the action entered is not a valid number.");
count = 0;
}
else
count = 1;
Your mistake is because you use OR operator.
For example user print 3. In your statements one condition return false (input != 3), but all others return true.. That's why you always go into if condition..
You can use AND operator, but I can recommend you to simplify your condition. It will be more understandable and readable:
var count = 0;
do
{
Console.Write("\n\nUser Input:");
int user_input;
if ((int.TryParse(Console.ReadLine(), out user_input) == false) || (user_input < 0 || user_input > 5))
{
Console.WriteLine("Error : the action entered is not a valid number.");
count = 0;
}
else
count = 1;
}
while (count != 1);
You already got an answer about the problem with predicate logic. But you can even more simplify with linq like:
var count = (new string[]{"1","2","3","4","5"}).Contains(Console.ReadLine()) ? 1 : 0;

Ternary operator in actualization of a loop

I am trying to make two loops into one. This Loop should go through the array from the beginning to the end and otherwise. However my increment is not correct. Can anyone help? Thank you in advance.
for (int i = ((asc == true) ? 0 : calendar.Length - 1);
((asc == true) ? i < calendar.Length : i > 0);
(asc==true) ? i++ : i--)
Personally, I find that very hard to read, as well as invalid (it won't compile) - because you're trying to use the conditional operator as a statement expression, when it's not. Personally, I'd write something like:
for (int i = 0; i < calendar.Length; i++)
{
int index = asc ? i : calendar.Length - 1 - i;
// Now use index...
}
Making three different aspects all conditional feels like a nasty way to go.
Look at the C# reference of "for": http://msdn.microsoft.com/en-us/library/ch45axte.aspx
Specifically:
The iterator section defines what happens after each iteration of the body of the loop. The iterator section contains zero or more of the following statement expressions, separated by commas:
assignment statement
invocation of a method
prefix or postfix increment expression, such as ++i or i++
prefix or postfix decrement expression, such as --i or i--
creation of an object by using new
await expression
The expression: "(asc==true) ? i++ : i--" is none of these things.
Therefore, you'd want the assignment: i += (asc ? 1 : -1)
for (int i = ((asc) ? 0 : calendar.Length - 1);
((asc) ? i < calendar.Length : i >= 0);
i += (asc) ? 1 : -1)
Incidentally, as pointed out in comment, you'll probably want to look at index 0 in the condition, so your condition statement in the "descending" case should be i >= 0 (reflected in the code).
Jon offered a good option, but if principle:
for (int i = (asc ? 0 : calendar.Length - 1);
asc ? i < calendar.Length : i >= 0;
i += asc?1:-1)
{
//body
}
That for loop is... odd. It is also very hard to read. In the spirit of "better ways to do this", I would suggest just using Reverse:
IEnumerable<Day> collection = asc ? calendar : calendar.Reverse();
for (int i = 0; i < calendar.Length; i++)
{
collection.ElemantAt(i);// This is the current element
}
//Or better, you are getting everything anyways:
foreach (Day day in collection)
{
}

C# ?: Expression

I have a function with multiple if's (THIS IS NOT THE ACTUAL CODE)
if(n == 1)
m = 1;
if(n == 2)
m = 2;
if(n == 3)
m = 3;
Instead of that I wanted to do make them all into ?: expression :
(n == 1) ? m = 1;
But it says that its expecting a ':'
I am familiar with the ?: expression from C++ where you can simply write:
(n == 1) ? m = 1 : 0;
But 0 doesn't take here. This is a ridiculous question and I couldn't even find an answer in google since it ignores '?:' as a word.
ANSWER : too bad the answer was in the comments. There is no way to "do nothing" in this expression and I should use if-else or switch. thanks.
It looks like you're looking for:
m = (n == 1) ? 1 : 0;
Which you could then cascade to:
m = (n == 1) ? 1 : (n == 2) ? 2 : (n == 3) ? 3 : 0;
An important (to me, anyway), aside:
Why are you asking this? If it's because you think that this form will be more efficient than a series of if statements, or a switch, don't. The C# compiler and the .net JIT compiler are really quite clever and they'll transform your code (hopefully!) into its most optimal form. Write your code so its as understandable by yourself, or the developer who has to maintain it after you as it can be. If the performance you get isn't acceptable, then try changing it around but measure to determine what works best (bearing in mind that newer compilers/.net frameworks could well change what happens).
looking for ternary operator in c# will give you relevant results.
an example usage would be
var m = n == 1 ? 1 : 0
Maybe:
m = (n == 1) ? 1 : (n == 2) ? 2 : (n == 3) ? 3 : m;
or
m = n
Edit:
Simplified:
variable2 = (variable1 == value) ?
variable1 :
variable2;
You want this:
m = (n == 1) ? 1 : 0;
To nest them all it would look like this:
m = (n == 1) ? 1 : (n == 2) ? 2 : (n == 3) ? 3 : 0;
But as you can see, this is really a lot less easy to read and understand. It can help to add extra parenthesis, but I think you're better off using an if-else tree.
m = (n == 1) ? 1 : m
Means
M equals 1 if n == 1, else m
FYI the ? is called the Ternery operator. Find usage on MSDN
Best regards,
You could write:
m = (n==1) ? 1 : m;
But IMO that's harder to read and uglier than the original code.
(n == 1) ? m = 1 : 0;
This isn't allowed because C# doesn't allow arbitrary expressions as a statement. Method calls and assignments are allowed, most other expressions aren't.
A statement is executed for its side-effects, an expression for its value. So it's only natural that the outermost part of a statement has a side effect. ?: never has a side-effect, so it's not allowed as a statement.
Try this :
m = (n == 1) ? 1 : 0;
This is not a problem to be solved with a ternary if/else operator - it is clearly an ideal candidate for a switch statement (and using a switch is likely to be much more efficient than using a sequence of ternary operators)
If you wish to transliterate an if statement into ?:, then it's quite simple:
if ({condition}) {then-code}; else {else-code};
becomes
{condition} ? {then-code} : {else-code};
The only restriction is that the then/else code is a single statement.
The primary benefit of ?: (with modern compilers) is that it can be embedded within a statement to significantly compress the source code - sometimes this can aid readability, and sometimes it just serves to obfuscate the meaning of the code - use it with care.

Does Lists in C# support slicing like in Python?

Sorry for such a basic question regarding lists, but do we have this feature in C#?
e.g. imagine this Python List:
a = ['a','b,'c']
print a[0:1]
>>>>['a','b']
Is there something like this in C#? I currently have the necessity to test some object properties in pairs. edit: pairs are always of two :P
Imagine a larger (python) list:
a = ['a','a','b','c','d','d']
I need to test for example if a[0] = a[1], and if a[1] = a[2] etc.
How this can be done in C#?
Oh, and a last question: what is the tag (here) i can use to mark some parts of my post as code?
You can use LINQ to create a lazily-evaluated copy of a segment of a list. What you can't do without extra code (as far as I'm aware) is take a "view" on an arbitrary IList<T>. There's no particular reason why this shouldn't be feasible, however. You'd probably want it to be a fixed size (i.e. prohibit changes via Add/Remove) and you could also make it optionally read-only - basically you'd just proxy various calls on to the original list.
Sounds like it might be quite useful, and pretty easy to code... let me know if you'd like me to do this.
Out of interest, does a Python slice genuinely represent a view, or does it take a copy? If you change the contents of the original list later, does that change the contents of the slice? If you really want a copy, the the LINQ solutions using Skip/Take/ToList are absolutely fine. I do like the idea of a cheap view onto a collection though...
I've been looking for something like Python-Slicing in C# with no luck.
I finally wrote the following string extensions to mimic the python slicing:
static class StringExtensions
{
public static string Slice(this string input, string option)
{
var opts = option.Trim().Split(':').Select(s => s.Length > 0 ? (int?)int.Parse(s) : null).ToArray();
if (opts.Length == 1)
return input[opts[0].Value].ToString(); // only one index
if (opts.Length == 2)
return Slice(input, opts[0], opts[1], 1); // start and end
if (opts.Length == 3)
return Slice(input, opts[0], opts[1], opts[2]); // start, end and step
throw new NotImplementedException();
}
public static string Slice(this string input, int? start, int? end, int? step)
{
int len = input.Length;
if (!step.HasValue)
step = 1;
if (!start.HasValue)
start = (step.Value > 0) ? 0 : len-1;
else if (start < 0)
start += len;
if (!end.HasValue)
end = (step.Value > 0) ? len : -1;
else if (end < 0)
end += len;
string s = "";
if (step < 0)
for (int i = start.Value; i > end.Value && i >= 0; i+=step.Value)
s += input[i];
else
for (int i = start.Value; i < end.Value && i < len; i+=step.Value)
s += input[i];
return s;
}
}
Examples of how to use it:
"Hello".Slice("::-1"); // returns "olleH"
"Hello".Slice("2:-1"); // returns "ll"

Categories