簡體   English   中英

適用於任意深度列表的函數

[英]Function that applies to lists of arbitrary depth

你如何編寫一個可以應用於任意深度列表的函數? 我將給出兩個我想用C#編寫的函數類型的例子。

示例1:可以在任何列表上使用的depth()方法:

int depth<T>(this List<T> x) {
    if (/*x[0] is a List<of something>*/) { return x[0].depth + 1; }
    else { return 1; }
}

示例2:一個implode()方法,可以在任何深度的字符串列表中使用:

List<List<string>> first = /* ("a","b"),("x","y","z") */
List<string> second = /* "a","b","c" */
first.implode() /* returns a string: "(a,b),(x,y,z)" */
second.implode() /* returns a string: "a,b,c" */

但我無法弄清楚如何制作適用於C#中任意深度列表的函數。

你這里有兩個問題; 試着每個帖子只問一個問題。 您可以像這樣計算深度函數:

static int Depth(Type type)
{
    int depth = 0;
    for(
        Type current = type; 
        current.IsGenericType && current.GetGenericTypeDefinition() == typeof(List<>) ;
        current = current.GetGenericArguments()[0] )
    {
        depth += 1;
    }
    return depth;
}

static int Depth<T>(this List<T> x) 
// x is unused; you could eliminate it entirely. 
{
    return Depth(typeof(List<T>));
}

您可以輕松地創建一個通用方法來下降集合(或集合集)。 我已經包含了示例DepthImplode方法。 另請注意,不使用Depth方法的參數(Eric在他的回答中也提到過)。 您可以從Depth方法的簽名中輕松省略參數,並將default(List<TElement>)傳遞給Descend方法。

/// <summary>
/// Extension methods for lists (or lists of lists)
/// </summary>
public static class ListExtensions
{
    /// <summary>
    /// Cache the generic method definition for <see cref="Descend{TElement, TResult}"/>
    /// </summary>
    private static readonly MethodInfo DescendMethod = new Func<List<object>, Func<object, object>, Func<IEnumerable<object>,object>, object>(Descend).Method.GetGenericMethodDefinition();

    /// <summary>
    /// Descends a potentially nested set of enumerables
    /// </summary>
    /// <typeparam name="TElement">The current enumerable type</typeparam>
    /// <typeparam name="TResult">The type of the result of the calling method</typeparam>
    /// <param name="set">The set of elements to work on</param>
    /// <param name="compute">The computation to perform on a single element</param>
    /// <param name="aggregate">The computation to perform on a collection of results from computations on single elements</param>
    /// <returns>The result of the aggregation of all the results from all levels of the set</returns>
    private static TResult Descend<TElement, TResult>(this List<TElement> set, Func<object, TResult> compute, Func<IEnumerable<TResult>, TResult> aggregate)
    {
        var elementType = typeof(TElement);

        if (elementType.IsGenericType && typeof(List<>) == elementType.GetGenericTypeDefinition())
        {
            var method = DescendMethod.MakeGenericMethod(elementType.GetGenericArguments()[0], typeof(TResult));

            if (ReferenceEquals(set, null))
            {
                return aggregate(new[] { (TResult)method.Invoke(null, new object[] { default(TElement), compute, aggregate }) });
            }

            var results = set.Select(item => (TResult)method.Invoke(null, new object[] { item, compute, aggregate })).ToList();

            if (results.Count == 0)
            {
                return aggregate(new[] { (TResult)method.Invoke(null, new object[] { default(TElement), compute, aggregate }) });
            }

            return aggregate(results);
        }

        return aggregate((set ?? new List<TElement>()).OfType<object>().Select(compute));
    }

    /// <summary>
    /// Walks down a set (possibly of sets) to determine its depth
    /// </summary>
    /// <typeparam name="TElement">The type of elements found in the top level set</typeparam>
    /// <param name="set">The set to walk down</param>
    /// <returns>The depth of the set</returns>
    public static int Depth<TElement>(this List<TElement> set)
    {
        return set.Descend(x => 0, x => x.FirstOrDefault() + 1);
    }


    /// <summary>
    /// Walks down a set (possibly of sets) to determine its depth
    /// </summary>
    /// <typeparam name="TElement">The type of elements found in the top level set</typeparam>
    /// <returns>The depth of the set</returns>
    public static int Depth<TElement>()
    {
        return Descend(default(List<TElement>), x => 0, x => x.FirstOrDefault() + 1);
    }

    /// <summary>
    /// Creates a string representation of a set (possibly of sets)
    /// </summary>
    /// <typeparam name="TElement">The type of elements found in the top level set</typeparam>
    /// <param name="set">The set to create the string representation of</param>
    /// <returns>A string representation of the set</returns>
    public static string Implode<TElement>(this List<TElement> set)
    {
        var result = set.Descend(x => x != null
                                          ? x.ToString()
                                          : null,
                                 x =>
                                 {
                                     var elements = x.Where(y => !ReferenceEquals(y, null)).ToList();

                                     if (elements.Count == 0)
                                     {
                                         return null;
                                     }

                                     return "(" + String.Join(",", elements) + ")";
                                 });

        if (result != null && result.Length > 2)
        {
            return result.Substring(1, result.Length - 2);
        }

        return result;
    }
}

class Program
{
    private static void Main()
    {
        var tmp2 = new List<List<List<List<string>>>>();
        var tmp = new List<List<List<string>>>
            {
                new List<List<string>>
                {
                    new List<string>
                    {
                        "1",
                        "2",
                        "3"
                    },
                    new List<string>
                    {
                        "4"
                    }
                },
                new List<List<string>>
                {
                    new List<string>
                    {
                        "5",
                        "6",
                        "7"
                    }
                }
            };

        Console.WriteLine(ListExtensions.Depth<List<List<List<List<string>>>>>());
        Console.WriteLine(tmp2.Depth());
        Console.WriteLine(tmp2.Implode());

        Console.WriteLine(tmp.Depth());
        Console.WriteLine(tmp.Implode());

        Console.ReadLine();
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM