简体   繁体   中英

Lambda expression as function parameter

I have the following code

List<int> GetIndices<T>(List<T> list, ?????? condition
{
    var result =
            list
                .Select((p, index) => index)
                .Where(condition);

    return result.ToList();
}

And I would like to call it like GetIndices(someList, (p, index) => (someList[index].Height < someList[index - 1].Height))

What is the correct type of condition ?

There's an error in your code: Where expects a delegate that returns a bool value and has the list element type as input.

var result = list
   .Select((p, index) => index) // projects the element to it's index (of type int)
   .Where(condition);           // => expects Func<int, bool>

So you would need Func<int,bool>

However, from your spec I think you want Func<T,int,bool> , which means you have to rewrite your implementation of GetIndices as

var result = list
   .Select((p, index) => new {p, index}) 
   .Where(x => condition(x.p, x.index))
   .Select(x => x.index);  
Func<T, bool>

Should do the trick but you're going to have to modify your lambda a bit because you can't pass the index (if you want to use condition in the Where clause). You could easily change your lambda to:

p => someList[someList.IndexOf(p).Height < someList[someList.IndexOf(p)-1].Height

For future reference, the MSDN documentation for the extension methods is great once you learn how to read it (that part takes a bit):

MSDN - Enumerable.Where Method

Since this is an extension method, the first parameter ( IEnumerable<TSource> ) is the collection you're calling the method on ( List<T> in your case).

The second parameter is what you need to match. Since the documentation calls for Func<TSource, bool> and TSource is T in your case...you get Func<T, bool>

Like jeroenh realized, you need to capture the original index. The Funct<T,int,bool> condition you pass only needs to be aware of the item and its index, not the anonymous type created in the query, so the condition passed changes a bit. It also should handle the situation where the index == 0 and therefore there are no preceding items (index - 1).

class Program {
    static void Main( string[] args ) {
        var items = Item.GetItems();
        // mind the case where index == 0 so you don't grab an item out of bounds
        var ind = GetIndices( items,
            ( p, index ) => ( h.index == 0 ) ? false : p.Height < items[ index - 1 ].Height );
    }

    static List<int> GetIndices<T>( List<T> list, Func<T, int, bool> condition ) {
        var res = list
            .Select( ( item, index ) => new { item, index } ) // capture original index
            .Where( h => condition( h.item, h.index ) )
            .Select( h => h.index ); // reduce to the index again
        return res.ToList();
    }
}

class Item {
    public int Height {
        get;
        set;
    }
    public Item( int h ) {
        Height = h;
    }
    static public List<Item> GetItems() {
        return new List<Item>( new[]{
                     new Item(1),
                     new Item(4),
                     new Item(2),
                     new Item(5)
        } );
    }
}

Try Func<bool> .

Or rather a variant with the correct amount of input parameters.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM