Problem with default value with lambda in Where function c# [duplicate] - c#

This question already has answers here:
C# compiler error: "not all code paths return a value"
(9 answers)
Closed 2 years ago.
I have a task to find even or odds numbers in a list using LINQ lambda.
I simply have this code to do it, but the compiler says "not all code paths return a value in lambda expression". So I think I need a default value, but how can I implement it? I tried a few things but still don't work. Please give advice. Thanks.
list = list.Where(x =>
{
if (command == "odd")
return x % 2 != 0;
else if (command == "even")
return x % 2 == 0;
});

If the command is "notEvenOrOdd" what should be the result? The example code does not cover this case, and it will therefore fail.
Using a "command" to determine what to do is usually not a great design. An alternative would be two extension methods:
public static IEnumerable<int> WhereEven(this IEnumerable<int> list) => list.Where(x => x % 2 != 0);
public static IEnumerable<int> WhereOdd(this IEnumerable<int> list) => list.Where(x => x % 2 == 0);
You can then check the command outside the lambda and run one of the methods above depending on the result.

I meant if the if-else statement dont match the conditions. I tried this and it works.
list = list.Where(x =>
{
if (command == "odd")
return x % 2 != 0;
else if (command == "even")
return x % 2 == 0;
return false;
}).ToList();

Related

s => s == 'w' - Help me understand this line of code [duplicate]

This question already has answers here:
Can you explain lambda expressions? [duplicate]
(6 answers)
What does the '=>' syntax in C# mean?
(7 answers)
Closed 4 years ago.
I am new to C# and coding in general and have a question on one exercise I'm doing. I am following the exercises on w3resource and I came across a challenge where I have to solve this:
"Write a C# program to check if a given string contains 'w' character between 1 and 3 times."
My solution was this:
var theString = Console.ReadLine();
var theArray = theString.ToCharArray();
int betweenOneAndThree = 0;
for (int i = 0; i < theArray.Length - 1; i++)
{
if (theArray[i] == 'w')
betweenOneAndThree++;
}
Console.WriteLine(betweenOneAndThree >= 1 && betweenOneAndThree <= 3);
Console.ReadLine();
This worked just fine, but I checked their solution and it goes like this:
Console.Write("Input a string (contains at least one 'w' char) : ");
string str = Console.ReadLine();
var count = str.Count(s => s == 'w');
Console.WriteLine("Test the string contains 'w' character between 1 and 3 times: ");
Console.WriteLine(count >= 1 && count <= 3);
Console.ReadLine();
I can't see 's' being declared as a char variable and I do not understand what it does here. Can anyone please explain to me what s => s == 'w' does?
Yes, I have tried googling this. But I can't seem to find an answer.
Thank you in advance :)
This is a lambda expression.
In this case it declares an anonymous delegate which is passed to Count, whose signature for this overload specifies a Func<T, bool> which is a typed representation of an anonymous function which takes a T (the type of the object in the collection) and returns bool. Count() here will execute this function against each object in the collection, and count how many times it returned true.
str.Count(s => s == 'w') is basically a shortened way to say this:
result = 0;
foreach (char s in str)
{
if (s == 'w')
{
result += 1;
}
}
return result;
s => s == 'w' is Predicate delegate with lambda expression,
str.Count(s => s == 'w') simply counts the occurences of the characters w

What is the most compact way using LINQ to check whether an IEnumerable<int> is ordered? [duplicate]

This question already has answers here:
Native C# support for checking if an IEnumerable is sorted?
(5 answers)
Closed 6 years ago.
I figured out a very LINQy way to do it
bool isOrdered = ids.Skip(1).Concat(new List<int>() { int.MaxValue })
.Zip(ids, (y, x) => y >= x)
.All(z => z);
However, it is not very efficient or compact. Is there a better way?
Aggregate is a way to walk sequence and keep track of previous item(s)
(new int[]{1,2,3}).Aggregate(
new { IsSorted = true, Previous = int.MinValue },
(state, current) => new {
IsSorted = (state.IsSorted && current > state.Previous),
Previous = current})
.IsSorted
Unfortunately with Aggregate there is no way to stop early unlike with .Zip() solution where you can stop early with .All as you have in your sample.
var isOrdered = ids.Zip(ids.Skip(1), (curr, next) => curr <= next).All(x => x);
If you're willing to be a bit more constrained and assume that rather than IEnumerable<int> you had an IList<int> you could do this, which allows you to quit early:
ids.Skip(1).Select( (val,ix) => val >= ids.ElementAt(ix-1) ).All( x => x);
It would function for any enumerable but it would be O(n^2) in the case where ids is not an IList. If you need this to work for any IEnumerable than #AlexeiLevenkov's solution is the best one.

Compare multiple values in one condition [duplicate]

This question already has answers here:
Equality comparison between multiple variables
(14 answers)
Closed 7 years ago.
Int32 int1, int2, int3 = 123;
Given the above variables, how can I test that all of my variables have the value 123 without creating a collection to perform some Any or something on?
What I've Tried
if(int1 == int2 == int3 == 123)
{
// Fantastic code here
}
EDIT
I must apologise, I haven't been clear enough in my question. I'm fully aware of the && operator, I was asking with regard to 'elegance', i.e. how can I avoid repeating the value I want to compare against.
In the same way I have assigned all 3 integer variables the same value in one hit, I'd like to now make the comparison. It's looking as though there is no way of doing this, so far. I think I'm asking the impossible, I'll have to stick to the basic syntax and keep it simple.
You can create an usefull extension function:
public static bool EqualsAll<T>(this T val, params T[] values)
{
return values.All(v => v.Equals(val));
}
call it like:
bool res = 123.EqualsAll(int1,int2,int3);
You could try something like this, using the logical and operator:
if(int1 == 123 &&
int2 == 123 &&
int3 == 123)
{
}
if(int1 == 123 && int2 == 123 && int3 == 123) { // Code }
What your trying to achieve isn't possible the way you do it.
You have to separate it with &.
if(int1 == something && int2 == something && int3 == 123)
{
// Fantastic code here
}
This is how you should do it using && operator. You can check multiple conditions using this.
UPDATE :
As far as checking multiple values at one go is concerned, you can try making an array out those values and just fire a simple LINQ statement like this to check all of them for a particular value :
if (new[] { int1, int2, int3 }.All(x => x == 1))
Dont know if this fits into your requirement, just a suggestion though.

lambda expression foreach loop

I have the following code
int someCount = 0;
for ( int i =0 ; i < intarr.Length;i++ )
{
if ( intarr[i] % 2 == 0 )
{
someCount++;
continue;
}
// Some other logic for those not satisfying the condition
}
Is it possible to use any of the Array.Where or Array.SkiplWhile to achieve the same?
foreach(int i in intarr.where(<<condtion>> + increment for failures) )
{
// Some other logic for those not satisfying the condition
}
Use LINQ:
int someCount = intarr.Count(val => val % 2 == 0);
I definitely prefer #nneonneo's way for short statements (and it uses an explicit lambda), but if you want to build a more elaborate query, you can use the LINQ query syntax:
var count = ( from val in intarr
where val % 2 == 0
select val ).Count();
Obviously this is probably a poor choice when the query can be expressed with a single lambda expression, but I find it useful when composing larger queries.
More examples: http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
Nothing (much) prevents you from rolling your own Where that counts the failures. "Nothing much" because neither lambdas nor methods with yield return statements are allowed to reference out/ref parameters, so the desired extension with the following signature won't work:
// dead-end/bad signature, do not attempt
IEnumerable<T> Where(
this IEnumerable<T> self,
Func<T,bool> predicate,
out int failures)
However, we can declare a local variable for the failure-count and return a Func<int> that can get the failure-count, and a local variable is completely valid to reference from lambdas. Thus, here's a possible (tested) implementation:
public static class EnumerableExtensions
{
public static IEnumerable<T> Where<T>(
this IEnumerable<T> self,
Func<T,bool> predicate,
out Func<int> getFailureCount)
{
if (self == null) throw new ArgumentNullException("self");
if (predicate == null) throw new ArgumentNullException("predicate");
int failures = 0;
getFailureCount = () => failures;
return self.Where(i =>
{
bool res = predicate(i);
if (!res)
{
++failures;
}
return res;
});
}
}
...and here's some test code that exercises it:
Func<int> getFailureCount;
int[] items = { 0, 1, 2, 3, 4 };
foreach(int i in items.Where(i => i % 2 == 0, out getFailureCount))
{
Console.WriteLine(i);
}
Console.WriteLine("Failures = " + getFailureCount());
The above test, when run outputs:
0
2
4
Failures = 2
There are a couple caveats I feel obligated to warn about. Since you could break out of the loop prematurely without having walked the entire IEnumerable<>, the failure-count would only reflect encountered-failures, not the total number of failures as in #nneonneo's solution (which I prefer.) Also, if the implementation of LINQ's Where extension were to change in a way that called the predicate more than once per item, then the failure count would be incorrect. One more point of interest is that, from within your loop body you should be able to make calls to the getFailureCount Func to get the current running failure count so-far.
I presented this solution to show that we are not locked-into the existing prepackaged solutions. The language and framework provides us with lots of opportunities to extend it to suit our needs.

InvalidArgument error when calling LINQ First() method

So my problem is that i am getting an invalid argument error in this section of code. What it is meant to do is take a hand of cards and get the sum of their total value. Then if the value is greater than 21 it checks to see if any of the cards in the hand is an ace(or the type is == ace and it's card totalVal == 11) now my problem is the statement i have written for this will run regardless of if there is an ace in the hand or not and throws an error.
I was wondering if there is any other way i can write the statement below in order to get this to run correctly?
public int HandTotal()
{
int total = CurrentCards.Sum(n => n.Total);
**while ( total > 21 && CurrentCards.First(n => n.Type == 13 && n.Total == 11) !=null)**
{
CurrentCards.First(n => n.Type == 13).Total = 1;
total = CurrentCards.Sum(n => n.Total);
return total;
}
return total;
}
i've tried several different things including changing the != null into > 0 however that throws an invalid argument error saying that > cannot be used with this statement. Is there any other way that i can determine if CurrentCards.First(n => n.Type == 13 && n.Total == 11) is true or false?
Any help or suggestions are greatly appreciated.
Thank You
Instead of First, use Any with the predicate.
while(total > 21 && CurrentCards.Any(n => n.Type == 13 && n.Total == 11))
The First method throws an exception if there are no matching element.
You need to call FirstOrDefault, which can return null.
You should try using FirstOrDefault instead of First.First will throw an error if no elements a returned.
Also check that CurrentCards is not empty. Both First and FirstOrDefault will give an ArguementNullException if the IEnumumerable is empty.

Categories

Resources