if statement with multiple conditions instead of using AND - c#

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

Related

Code not returning expected number of even and odds

I have a function that takes in a list of numbers and will return how many even numbers and odd numbers there are in the list. However, I passed in a list of numbers but I'm getting 0 results.
Here is my function -
public static string HowManyEvenAndOdds(List<int> numbers)
{
int numOfOdds = 0;
int numOfEvens = 0;
int numOfBoth = 0;
foreach (int i in numbers) {
bool isEven = i % 2 == 0;
bool isOdd = i % 3 == 0;
numOfBoth = isEven && isOdd ? numOfBoth++ : numOfBoth;
numOfEvens = isEven ? numOfEvens++ : numOfEvens;
numOfOdds = isOdd ? numOfOdds++ : numOfOdds;
}
return string.Format("This list has {0} odd numbers,\n{1} even numbers,\nand {2} numbers that are even and odd.", numOfOdds, numOfEvens, numOfBoth);
}
Any ideas on what I'm doing wrong here? I debugged through it but none of the lists are incrementing.
Thanks
your are not calculating odd in the correct way
i%3 does not catch 5 which is also an odd number, try this instead
bool isEven = i % 2 == 0;
bool isOdd =!isEven;
I agree with Schachaf Gortler's answer as well as p.s.w.g's comment. Just do:
foreach (var number in numbers)
{
// A number is even if, and only if, it's evenly divisible by 2
if (number % 2 == 0)
numEvens++;
// A number is odd if, and only if, it's NOT evenly divisible by 2
// Alternatively, a number is odd if it isn't even and vice versa
else
numOdds++;
}
As p.s.w.g. mentioned, there's no such thing as a number that's both even and odd, so eliminate that completely.
Incidentally, numOfEvens++ retrieves the value and then increments it, which is why your code didn't work.
I think you should have a look at your test for isOdd
Use the Linq Count extension.
int numOfOdds = numbers.Count(x => x % 2 != 0);
int numOfEvens = numbers.Count(x => x % 2 == 0);
Of course you don't need to evaluate both expressions, as per the comment below.

Re-writing code to remove conditional statements

Is it possible to re-write the following so that it doesn't contain any conditional statements? I'm thinking there might be some clever trick using something like bitwise operations?
int a = // some value
int b = // some other value between 0 and max int
if(b >= 3)
{
return a + 1;
}
else
{
return a;
}
EDIT: to be clear, I'm not looking for a generic way of removing conditionals. I'm looking for a trick to remove the conditionals from this very specific code. Think of it as an academic puzzle.
To give an example, one way to remove conditionals (which happens to yield perf gains in some situations) is to precompute a lookup table and index into that with b instead. In this particular case this is tricky because b could be a very large number. Is there another way?
Here you go
return a - ((2 - b) >> 31);
Explanation:
r = 2 - b, < 0 (i.e. high bit set) for b >= 3
r >> 31, = -1 for b >= 3, 0 otherwise
uint a = // some value
uint b = // some other value between 0 and max int
bool c = b & 0xFFFC
return a + Convert.ToInt32(c);
The fastest will probably be as bitwise operations tend to be very fast
uint a = // some value
uint b = // some other value between 0 and max int
return (b & 0xFFFC) ? a+1 : a;
You could make it better by doing this:
int a = // some value
int b = // some other value between 0 and max int
return (b >= 3) ? (a+1) : a;
?: operator. (but yet it contains conditional statement.)
return b >= 3 ? a + 1 : a;
or
return a + (b >= 3 ? 1 : 0);
Is it possible to re-write the following so that it doesn't contain any conditional statements?
It is not possible to make it work out of no where. you must check this condition any way. There is no magic.
If you want to make your program faster by removing this condition then you picked wrong way. this is micro optimization.

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#: Choosing operator depending on boolean value (in one line)

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

c# optimizing cycle working with big numbers

I have this code that finds numbers in a given range that contain only 3 and 5 and are polynoms(symetrical, 3553 for example). The problem is that the numbers are between 1 and 10^18, so there are cases in which I have to work with big numbers, and using BigInteger makes the program way too slow, so is there a way to fix this ? Here's my code:
namespace Lucky_numbers
{
class Program
{
static void Main(string[] args)
{
string startString = Console.ReadLine();
string finishString = Console.ReadLine();
BigInteger start = BigInteger.Parse(startString);
BigInteger finish = BigInteger.Parse(finishString);
int numbersFound = 0;
for (BigInteger i = start; i <= finish; i++)
{
if (Lucky(i.ToString()))
{
if (Polyndrome(i.ToString()))
{
numbersFound++;
}
}
}
}
static bool Lucky(string number)
{
if (number.Contains("1") || number.Contains("2") || number.Contains("4") || number.Contains("6") || number.Contains("7") || number.Contains("8") || number.Contains("9") || number.Contains("0"))
{
return false;
}
else
{
return true;
}
}
static bool Polyndrome(string number)
{
bool symetrical = true;
int middle = number.Length / 2;
int rightIndex = number.Length - 1;
for (int leftIndex = 0; leftIndex <= middle; leftIndex++)
{
if (number[leftIndex] != number[rightIndex])
{
symetrical = false;
break;
}
rightIndex--;
}
return symetrical;
}
}
}
Edit: Turns out it's not BigInteger, it's my shitty implementation.
You could use ulong:
Size: Unsigned 64-bit integer
Range: 0 to 18,446,744,073,709,551,615
But I would guess that BigInteger is not a problem here. I think you should create algorithm for palindrome creation instead of brute-force increment+check solution.
Bonus
Here is a palyndrome generator I wrote in 5 minutes. I think it will be much faster than your approach. Could you test it and tell how much faster it is? I'm curious about that.
public class PalyndromeGenerator
{
private List<string> _results;
private bool _isGenerated;
private int _length;
private char[] _characters;
private int _middle;
private char[] _currentItem;
public PalyndromeGenerator(int length, params char[] characters)
{
if (length <= 0)
throw new ArgumentException("length");
if (characters == null)
throw new ArgumentNullException("characters");
if (characters.Length == 0)
throw new ArgumentException("characters");
_length = length;
_characters = characters;
}
public List<string> Results
{
get
{
if (!_isGenerated)
throw new InvalidOperationException();
return _results.ToList();
}
}
public void Generate()
{
_middle = (int)Math.Ceiling(_length / 2.0) - 1;
_results = new List<string>((int)Math.Pow(_characters.Length, _middle + 1));
_currentItem = new char[_length];
GeneratePosition(0);
_isGenerated = true;
}
private void GeneratePosition(int position)
{
if(position == _middle)
{
for (int i = 0; i < _characters.Length; i++)
{
_currentItem[position] = _characters[i];
_currentItem[_length - position - 1] = _characters[i];
_results.Add(new string(_currentItem));
}
}
else
{
for(int i = 0; i < _characters.Length; i++)
{
_currentItem[position] = _characters[i];
_currentItem[_length - position - 1] = _characters[i];
GeneratePosition(position + 1);
}
}
}
}
Usage:
var generator = new PalyndromeGenerator(6, '3', '5');
generator.Generate();
var items = generator.Results.Select(x => ulong.Parse(x)).ToList();
Strange riddle, but can be simplified if I understand the requirement.
I would first map these numbers to binary as there is only two possible
"lucky" digits, then generate the numbers by counting in binary until
I have completed nine bits. Reflect it for the full number, then
convert 0 to 3 and 1 to 5.
Example 1101
Reflect it = 10111101 --> 53555535
Do this from 0 all the way to 111111111
Declare start and finish to be static inside the class.
Change the method Lucky to:
static bool Lucky(string number)
{
return !(number.Contains("1") || number.Contains("2") || number.Contains("4") || number.Contains("6") || number.Contains("7") || number.Contains("8") || number.Contains("9") || number.Contains("0"));
}
Also, you can use Parallel library to parallelize the computation.
Instead of using a regular for loop, you could use a Parallel.For.
Look at the problem a different way - how many strings of up to 9 characters (using only '3' and '5') can you make? for each string you have 2 palindromes (one repeating the last character, one not) that you can make.
e.g.
3 -> 33
5 ->, 55
33 -> 333, 3333
35 -> 353, 3553
53 -> 535, 5335
...
The only suggestion I have is to use a 3rd party library like intx, or some unmanaged code. The intx author reports that it can work faster than BigInteger in some situations: "System.Numerics.BigInteger class was introduced in .NET 4.0 so I was interested in performance of this solution. I did some tests (grab test code from GitHub) and it appears that BigInteger has performance in general comparable with IntX on standard operations but starts losing when FHT comes into play (when multiplying really big integers, for example)."
Since the number has to be symmetrical, you only need to check the first half of the number. You don't need to check 18 digits, you only have to check to 9 digits and then swap the order of the characters and add them to the back as a string.
One thing I can think of is if you are only going to count integers that are containing 3 or 5 you don't need to traverse the entire list of numbers between your beginning & ending range.
Instead, look at your character set as either '3' or '5'. Then you can simply go through the allowed permutations of half of the number itself, leaving the other half to be completed to successfully create a polyndrome.
There are some rules to this method which would help, such as :
if the starting number's left-most digit was greater than 5 there is no need to attempt for that specific number of digits.
if both numbers fall on the same amount of digits but left-most digits do not traverse / include 5 or 3, no need to process.
Developing some set of rules such as this may help other than attempting to check every possible permutation.
So, for example, your Lucky function would become something more along the lines of :
static bool Lucky(string number)
{
if((number[0] != '3') && (number[0] != '5'))
{
return false;
} //and you could continue this for the entire string
...
}

Categories