![](/img/trans.png)
[英]How can I flatten nested collection using GetProperties() in C#
[英]how to flatten nested tuples in c#?
我有嵌套的元組,比如 - Tuple<Tuple<Tuple<string,string>, string>, string>
。 我想像Tuple<string,string,string,string>
一樣扁平化它們。 我看到這可以在 f# 中完成。 是否有一個版本的 - F# 扁平化嵌套元組- 在 C# 中
假設你堅持使用這個相當令人討厭的設計,你可以這樣做:
/// <summary>
/// Constructs a tuple our of an array of arguments
/// </summary>
/// <typeparam name="T">The type of argument.</typeparam>
/// <param name="values">The values.</param>
/// <returns></returns>
public static object ConstructTuple<T>(params T[] values)
{
Type genericType = Type.GetType("System.Tuple`" + values.Length);
Type[] typeArgs = values.Select(_ => typeof(T)).ToArray();
Type specificType = genericType.MakeGenericType(typeArgs);
object[] constructorArguments = values.Cast<object>().ToArray();
return Activator.CreateInstance(specificType, constructorArguments);
}
/// <summary>
/// Flattens a tupple into an enumeration using reflection.
/// </summary>
/// <typeparam name="T">The type of objects the nested tuple contains.</typeparam>
/// <param name="tuple">The tuple to flatten.</param>
/// <returns></returns>
public static IEnumerable<T> FlattenTupple<T>(object tuple)
{
List<T> items = new List<T>();
var type = tuple.GetType();
if (type.GetInterface("ITuple") == null)
throw new ArgumentException("This is not a tuple!");
foreach (var property in type.GetProperties())
{
var value = property.GetValue(tuple);
if (property.PropertyType.GetInterface("ITuple") != null)
{
var subItems = FlattenTupple<T>(value);
items.AddRange(subItems);
}
else
{
items.Add((T)value);
}
}
return items;
}
示例用法:
Tuple<Tuple<Tuple<string, string>, string>, string> tuple =
new Tuple<Tuple<Tuple<string, string>, string>, string>(new Tuple<Tuple<string, string>, string>(new Tuple<string, string>("value1", "value2"), "value2b"), "value2c");
var items = FlattenTupple<string>(tuple);
var flattened = ConstructTuple(items.ToArray());
Console.WriteLine(flattened);
輸出:
(value1, value2, value2b, value2c)
示例 2(整數):
Tuple<Tuple<Tuple<int, int>, int>, int> intTuple =
new Tuple<Tuple<Tuple<int, int>, int>, int>(new Tuple<Tuple<int, int>, int>(new Tuple<int, int>(1, 2), 3), 4);
var intItems = FlattenTupple<int>(intTuple);
var flattened2 = ConstructTuple(intItems.ToArray());
Console.WriteLine(flattened2);
輸出:
(1, 2, 3, 4)
您可以使用遞歸和深度優先搜索將Tuple
轉換為平面列表。 試試這個方法:
public static IEnumerable<object> DFS(object t)
{
var type = t.GetType();
if (type.FullName?.StartsWith("System.Tuple") != true) // or check inheritanse from ITuple
yield return t;
var items = type.GetProperties()
.Where(p => p.Name.StartsWith("Item"))
.Select(p => p.GetValue(t))
.ToArray();
foreach (var item in items)
{
foreach (var innerItem in DFS(item))
{
yield return innerItem;
}
}
}
你可以這樣使用它:
var input = Tuple.Create(Tuple.Create(Tuple.Create("a0", "a1"), "a2"), "b", "c");
var items = DFS(input).ToArray();
// items[2] would be "a2"
請注意,反射可能會減慢您的應用程序的速度,因此請盡量避免它
如果您只有一個項目,則創建一個更易於管理的轉換器,尤其是如果您最終擁有一個List
。
public Tuple<string, string, string, string> ConvertSomething(Tuple<Tuple<Tuple<string,string>, string>, string> original)
{
return new Tuple<string, string, string, string>
(
original.Item1.Item1.Item1,
original.Item1.Item1.Item2,
original.Item1.Item2,
original.Item2
);
}
請注意, Tuple
並不打算在此過程中進行修改。 如果您確實需要它,則意味着您的設計實際上非常糟糕。 最好的解決方案仍然是重新思考事情是如何運作的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.