开发者

Using generics to make an algorithm work on lists of "something" instead of only String's

I have a small algorithm which replaces the position of characters in a String:

class Program
{
    static void Main(string[] args)
    {
        String pairSwitchedStr = pairSwitch("some short sentence");
        Console.WriteLine(pairSwitchedStr);

        Console.ReadKey();
    }

    private static String pairSwitch(String str)
    {
        StringBuilder pairSwitchedStringBuilder = new StringBuilder();
        for (int position = 0; position + 1 < str.Length; position += 2)
        {
            pairSwitchedStringBuilder.Append((char)str[position + 1]);
            pairSwitchedStringBuilder.Append((char)str[position]);
        }
        return pairSwitchedStringBuilder.ToString();
    }
}

I would like to make it as generic as possible, possibly using Generics. What I'd like to have is something which works with:

  • Anything that is built up using a list of instances.
  • Including strings, arrays, linked lists

I suspect that the solution must use generics as the algorithm is working on a list of instances of T (there T is ... something). Version of C# isn't of interest, I guess the solution will be nicer if features from C# version >2.0 is used.

I ended up with: (Where I fixed the error in the above code, it didn't handle odd lengths correctly)

    private static IEnumerable<T> switchSubstitutionCipher<T>(IEnumerable<T> input)
    {
        bool even = false;
        T lastItem = default(T);

        foreach (T element in input)
        {
            if (even) {
    开发者_JS百科            yield return element;
                yield return lastItem;
            }

            even = !even;
            lastItem = element;
        }
        if (even)
            yield return lastItem;
    }


Strings, in C#, are conceptually very different than an array or linked list. Although a string does implement IEnumerable<Char>, it is an immutable class, so you can't work with it like an IList<T> or Array.

I would recommend leaving your string implementation, then adding a generic implementation for any IList<T>:

private static IList<T> pairSwitch<T>(IList<T> original)
{
    List<T> results = new List<T>(original.Count);

    for (int i=0;i<original.Count-1;i+=2)  // Using -1 to make sure an odd number doesn't throw...
    {
        results.Add(original[i+1]);
        results.Add(original[i]);
    }
    return results;
}


    private static IEnumerable<T> pairSwitch<T>(IEnumerable<T> input)
    {
        T current = default(T);     // just to satisfy compiler
        bool odd = true;
        foreach (T element in input)
        {
            if (odd) current = element;
            else
            {
                yield return element;
                yield return current;
            }
            odd = !odd;
        }
    }

    static void Main(string[] args)
    {
        string test = "Hello";
        string result = new string(pairSwitch(test).ToArray());

Benefits:

  1. Lazy evaluation - which might be important for big lists

  2. String implementation is handled using IEnumerable implementation.


Alternatively, you could use something like this:

public static class SwitchUtilities
{
    public static IEnumerable<T> PairSwitch<T>(this IEnumerable<T> source)
    {
        T lastItem = default(T);
        bool odd = true;

        foreach(T value in source)
        {
            if(odd)
            {
                lastItem = value;
                odd = false;
            }
            else
            {
                yield return value;
                yield return lastItem;

                odd = true;
            }        
        }
    }
}

This would work to switch pairs of any IEnumerable<T> sequence, which would include string. The only issue here would be that you would get back an IEnumerable<char> rather than a string, but this is easily corrected with:

string value = new String("some short sentence".PairSwitch().ToArray());
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜