Click here to Skip to main content
15,899,314 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I would like to know how to get the index of an object from a LINQ query in addition to the result set itself. Once I have the index of the result set, I would like to remove the item from the same list I am querying.

Base Class: Animal
Derived Class: Fish : Animal

//Fish has a Scales property

What I have tried:

Currently my code looks like this and works perfectly but I want to get the actual item/index so I can remove it from NoahsArk when i'm done with it.

List<animal> NoahsArk = new List<animal>();

//just assume separate code populates this list (NoahsArk) with a bunch of random
//animals and that there are a bunch of fish in the list

var FishQuery = NoahsArk.Where(f => f is Fish).OrderByDescending (f => (f as Fish).Scales)

Fish f = FishQuery.Cast<fish>().First();


1) Now that I have the fish I want (a fish with the highest amount of scales), I want to remove that specific fish from NoahsArk by index (or some other method if that's easier).

2) Is there a way to condense the cast line into the LINQ query creation line to make it more condense? IF not that's totally fine and not the main issue. My main issue with the first question.
Posted
Updated 27-May-21 9:50am

Use .Remove(); it removes the instance; you don't need the index in this case.

List<T>.Remove(T) Method (System.Collections.Generic) | Microsoft Docs[^]
 
Share this answer
 
First off, you code won't compile:
1) C# is case sensitive, so Fish and fish are different classes.
2) You can't use f as a lambda parameter, because you are using f as a Fish in the outer method - you can't have two variables in the same scope with the same name (and yes, yes - I know the lambda parameter scope is restricted to the expression: the compiler doesn't and will complain!)
3) Don't forget your semicolons! :laugh:

Having said that, if you use Cast earlier you get a clearer result:
C#
Fish fish = NoahsArk.Where(f => f is Fish).Cast<Fish>().OrderByDescending(f => f.Scales).FirstOrDefault();
Note that I used FirstOrDefault - which returns a null if there were no Fishes on the boat!
I would probably enter is as:
C#
Fish fish = NoahsArk.Where(f => f is Fish)
                    .Cast<Fish>()
                    .OrderByDescending(f => f.Scales)
                    .FirstOrDefault();

As it's easier to read than a single line, but that's personal preference.

You definitely don't want to use an index to remove items as any index you could get would be indexing the input list as filtered by the Where which effectively creates a new sequence: If the input has ten items, and the last three are the ones you want, the index post Where would be 0 to 2 which doesn't reference any of them!
As Gerry said - use Remove rather than RemoveAt, it finds the instance and removes it which is much safer!
 
Share this answer
 
Comments
Giovanni Bejarasco 28-May-21 10:47am    
Hi OriginalGriff. I posted a solution that's very similar to yours and flagged as plagiarism by Richard Deeming. .Anyone looking at it would say Ijust renamed variables and add a line to actually remove the value. It was not my intention to plagiarize. It was just the rusher side of me - not reading thru the entire thread before posting. For me that was the correct answer and therefore YOU GAVE the correct answer. I sincerely apologize for the carelessness and I thanked Richard Deeming for pointing that out.
OriginalGriff 28-May-21 11:09am    
No problem - it happens, and I'm not worried. :D

Thank you for the apology anyway!
You can combine the .Where(f => f is Fish) and the cast by using .OfType<Fish>():
C#
Fish fish = NoahsArk.OfType<Fish>().OrderByDescending(f => f.Scales).FirstOrDefault();
Also, don't forget that FirstOrDefault will return null if there are no Fish in the ark. You'll need to check for null before trying to remove or examine the fish.

If you really want the index, you'll need to use an overload of Select:
C#
var fishWithIndex = NoahsArk
    .Select((animal, index) => new { fish = animal as Fish, index })
    .Where(pair => pair.fish != null)
    .OrderByDescending(pair => pair.fish.scales)
    .FirstOrDefault();

if (fishWithIndex != null)
{
    NoahsArk.RemoveAt(fishWithIndex.index);
    ShowFish(fishWithIndex.fish);
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900