开发者

How to specify a list selection method?

I've got a method that computes a list. At certain points in the algorithm a single element from the list needs to be chosen. It doesn't really matter which 开发者_Python百科element is chosen, but I'd like to leave it up to the user to decide.

Right now, I've added an extension method IList<T>.Random() which simply takes a random element. .First() would have worked equally as well. Supposing I want to let the user pick which method is used, or perhaps an entirely different method, how would that look?

I was thinking about using an enum with limited options, and then I could wrap each of these calls in a switch and call the appropriate function. But maybe some sort of lambda function would be more appropriate?

This method needs to be used in two different places, once on a List<char> and once on a List<string>. I want to use the same method for both.


This isn't a GUI app. I'm trying to decide how to design the API.

Specifically, I want to have a field like

public Func<IList<T>, T> SelectElement = list => list.First();

Which would then be used in the method,

 public string Reverse(string pattern, IList<object> args = null, IDictionary<string, object> kwargs = null)

But generic fields aren't possible. So I'm looking for an alternative solution. One would be to make the SelectElement method an argument to Reverse(), then I could make it generic... but I was hoping to keep it at a class-level for re-usability. Don't want to pass any more args to the function if I can help it.

Edit: full source code


how about this:


    public class MyClass
    {
        public static class C<T>
        {
            public static Func<IList<T>, T> SelectElement;
        }

        public int Test(IList<int> list)
        {
            return C<int>.SelectElement(list);
        }
    }

    static class Program
    {
        static void Main(string[] args)
        {
            MyClass.C<char>.SelectElement = xs => xs.First();
            MyClass.C<int>.SelectElement = xs => xs.First();

            var list = new List<int>(new int[] { 1, 2, 3 });

            var c = new MyClass();

            var v = c.Test(list);
            Console.WriteLine(v);
        }
    }


Here's an extremely basic example I put together using a generic method that takes in a Func<IEnumerable<T>, T> for selecting an item from the list and then returns the result. I've done a few examples of how to call it:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            //Simple list.
            var list = new List<int> { 1, 2, 3, 4 };

            // Try it with first
            var result = DoItemSelect(list, Enumerable.First);
            Console.WriteLine(result);

            // Try it with last
            result = DoItemSelect(list, Enumerable.Last);
            Console.WriteLine(result);

            // Try it with ElementAt for the second item (index 1) in the list.
            result = DoItemSelect(list, enumerable => enumerable.ElementAt(1));
            Console.WriteLine(result);
        }

        public static T DoItemSelect<T>(IEnumerable<T> enumerable, Func<IEnumerable<T>, T> selector)
        {
            // You can do whatever you method does here, selector is the user specified func for
            // how to select from the enumerable.  Here I just return the result of selector directly.
            return selector(enumerable);
        }
    }
}

If you want to limit the choices a user has you could follow the route of an enum and make this method a private method and then have a way to convert the enum to the appropriate selector delegate to pass to the underlying private method.


public Func<IList<object>, object> SelectElement = list => list.First();

private T _S<T>(IEnumerable<T> list)
{
    return (T)SelectElement(list.Cast<object>().ToList());
}

I can make the anonymous method work on objects, thereby avoiding generics, and then add a helper method which is what I'll actually use to call it. A little ugly, but seems to work.


This works for chars and strings. Haven't tested with other types. Built this before I saw Ralph's code, which is practically the same.

LINQPad code:

void Main()
{
    var chars = new List<char>(); 
    var strings = new List<string>(); 

    chars.AddRange(new char[] {'1','2','4','7','8','3'});
    strings.AddRange(new string[] {"01","02","09","12","28","52"}); 

    chars.Dump(); 
    strings.Dump(); 

    Func<IList<object>, string> SelectFirst = ( list ) 
        => list.First().ToString();
    Func<IList<object>, string> SelectLast = ( list ) 
        => list.Last().ToString();
    Func<IList<object>, string> SelectRandom = ( list ) 
        => list.ElementAt( new Random().Next(0, list.Count())).ToString(); 

    SelectBy(SelectFirst, strings.Cast<object>().ToList()).Dump(); 
    SelectBy(SelectFirst, chars.Cast<object>().ToList()).Dump(); 

    SelectBy(SelectLast, strings.Cast<object>().ToList()).Dump(); 
    SelectBy(SelectLast, chars.Cast<object>().ToList()).Dump(); 

    SelectBy(SelectRandom, strings.Cast<object>().ToList()).Dump(); 
    SelectBy(SelectRandom, chars.Cast<object>().ToList()).Dump(); 
}

private string SelectBy(Func<IList<object>, string> func, IList<object> list)
{   
    return func(list); 
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜