我有一个双打List<double[]>
列表,我想将其转换为List<T>
,其中T是一个类。
double数组包含17个值,例如[1.0,2.0,3.0,4.0,5.0,.. 17.0]。 然后我有一个类定义了17个字符串属性,例如P1,P2,....,P17
因此List<double[]>
的每个元素都是一个双精度数组,数组中的每个元素都代表T
类中属性的值。
是否可以将给定双打数组的每个索引映射到类型为T的类的属性。所以我将List<double[]>
转换为List<T>
,T
为{{1} }}
我知道可以通过手动迭代读取每个数组的列表来完成 从数组的每个索引读取值并将其传递给类的相应属性。 但是当我有10多个属性的课程时,要做很多事情。
编辑:其中一个类的示例如下所示
class
EDIT2 :从列表中创建列表的方法,注意 _profiler.FinalCentroid的类型为 /// <summary>
/// Defines the properties of a centroid.
/// </summary>
public class Centroid
{
// ReSharper disable InconsistentNaming
/// <summary>
/// Calls made to contacts
/// </summary>
public string CONTACT_CALLS { get; set; }
/// <summary>
/// Duration of calls made to contacts
/// </summary>
public string CONTACT_CALLS_SEC { get; set; }
/// <summary>
/// Calls made to non contacts
/// </summary>
public string UNKNOWN_CALLS { get; set; }
/// <summary>
/// Duration of calls made to non contacts
/// </summary>
public string UNKNOWN_CALLS_SEC { get; set; }
/// <summary>
/// Number of SMS sent to contacts
/// </summary>
public string SMS_OUT_CONTACTS { get; set; }
/// <summary>
/// Number of SMS sent to non contacts
/// </summary>
public string SMS_OUT_UNKNOWN { get; set; }
/// <summary>
/// Percentage of CPU usaed
/// </summary>
public string CPU_USAGE { get; set; }
/// <summary>
/// Percentage of RAM used
/// </summary>
public string RAM_USAGE { get; set; }
/// <summary>
/// Number of system application
/// </summary>
public string SYS_APPS { get; set; }
/// <summary>
/// Number of user applications
/// </summary>
public string USER_APPS { get; set; }
/// <summary>
/// Number of system services
/// </summary>
public string SYS_SERVICES { get; set; }
/// <summary>
/// Number of user services
/// </summary>
public string USER_SERVICES { get; set; }
/// <summary>
/// Number of bytes sent
/// </summary>
public string BYTES_TX { get; set; }
/// <summary>
/// Number of bytes received
/// </summary>
public string BYTES_RX { get; set; }
/// <summary>
/// Latitute of the location
/// </summary>
public string LOC_LAT { get; set; }
/// <summary>
/// Longitude of the location
/// </summary>
public string LOC_LON { get; set; }
/// <summary>
/// The Time Slice
/// </summary>
public string TIME_SLICE { get; set; }
// ReSharper restore InconsistentNaming
}
List<double[]>
答案 0 :(得分:5)
要发布明显的,为什么不在构造函数中分配属性?
您将开始创建属性的工作
在构造函数中分配值的键击次数少于属性。
List<double[]> ld = new List<double[]>();
List<PropDouble> lpd = new List<PropDouble>();
foreach (double[] da in ld) { lpd.Add(new PropDouble(da)); }
public class PropDouble
{
public double P0 { get; set; }
public double P1 { get; set; }
public PropDouble(double[] doubles) { P0 = doubles[0]; P1 = doubles[1]; }
}
或
public class PropDouble
{
private double[] doubles;
public double P0 { get { return doubles[0]; } set { doubles[0] = value; } }
public double P1 { get { return doubles[1]; } set { doubles[1] = value; } }
public PropDouble(double[] Doubles) { doubles = Doubles; }
}
答案 1 :(得分:2)
编辑:正如Blam所指出的那样,最明显的答案是一个简单的构造函数,我会更新这个答案以获得更复杂的场景。
假设您从不同位置获取阵列。它们可能有不同的顺序或可能缺少值。在这种情况下,您可以使用custom attributes和reflection将属性映射到不同的数组索引。每个映射都被命名,以便您可以为不同的数组使用不同的索引(或根本不使用)。
请注意,反射会大大降低性能。对于少数几个对象,这个成本几乎不值得注意,但是如果你要处理数千个或更多的对象,那么你可能需要考虑重构。
这是您用于将属性映射到索引的自定义属性
[AttributeUsage( AttributeTargets.Property, AllowMultiple = true )]
class ArrayToPropertyMap : Attribute
{
public string ArrayName
{
get;
set;
}
public int ArrayIndex
{
get;
set;
}
/* Call this function to do the actuall mapping (target is updated) */
public static IEnumerable<U> Map<U, T>( IEnumerable<T[]> source, string arrayName ) where U : new()
{
if ( !source.Any() )
return new U[] { };
var l_mappedProperties =
typeof( U )
.GetProperties( System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance )
.Where(
p => ( p.PropertyType == typeof( T ) ) && Attribute.IsDefined( p, typeof( ArrayToPropertyMap ) ) )
.Select(
p => new
{
Property = p,
Attribute = p.GetCustomAttributes( typeof( ArrayToPropertyMap ), true )
.Cast<ArrayToPropertyMap>()
.Where( a => a.ArrayName == arrayName )
.FirstOrDefault()
} )
.Where(
p => p.Attribute != null )
.Select(
p => new
{
Property = p.Property,
Index = p.Attribute.ArrayIndex
} );
var l_result = new List<U>();
foreach ( var array in source )
{
var l_target = new U();
foreach ( var l_mappedProperty in l_mappedProperties )
l_mappedProperty.Property.SetValue( l_target, array[l_mappedProperty.Index], null );
l_result.Add( l_target );
}
return l_result;
}
}
这是一个示例类(因此您可以看到它正常工作)
class LotsaProps1
{
[ArrayToPropertyMap( ArrayName = "Array1", ArrayIndex = 0 )]
[ArrayToPropertyMap( ArrayName = "Array2", ArrayIndex = 3 )]
public string Prop1
{
get;
set;
}
[ArrayToPropertyMap( ArrayName = "Array1", ArrayIndex = 2 )]
[ArrayToPropertyMap( ArrayName = "Array2", ArrayIndex = 2 )]
public string Prop2
{
get;
set;
}
/* Notice that Prop3 is not mapped to Array1 */
[ArrayToPropertyMap( ArrayName = "Array2", ArrayIndex = 1 )]
public string Prop3
{
get;
set;
}
[ArrayToPropertyMap( ArrayName = "Array1", ArrayIndex = 1 )]
[ArrayToPropertyMap( ArrayName = "Array2", ArrayIndex = 0 )]
public string Prop4
{
get;
set;
}
}
这部分只是运行示例
class Program
{
static void Main( string[] args )
{
/* You should already have the arrays... */
string[][] arr1 = new string[][] {
new string[] { "Value A 1", "Value A 2", "Value A 3" },
new string[] { "Value A 4", "Value A 5", "Value A 6" },
new string[] { "Value A 7", "Value A 8", "Value A 9" },
};
string[][] arr2 = new string[][] {
new string[] { "Value B 1", "Value B 2", "Value B 3", "Value B 4" },
new string[] { "Value B 5", "Value B 6", "Value B 7", "Value B 8" },
new string[] { "Value B 9", "Value B 10", "Value B 11", "Value B 12" },
};
/* ...so this is really the only code you'd need to add to your
business logic: */
var l_objs1 = ArrayToPropertyMap.Map<LotsaProps1, string>( arr1, "Array1" );
var l_objs2 = ArrayToPropertyMap.Map<LotsaProps1, string>( arr2, "Array2" );
/* This code is just used to show that the example works: */
Console.WriteLine( "Array1:" );
foreach ( var l_obj in l_objs1 )
{
Console.Write( "Prop1='" + l_obj.Prop1 + "'; " );
Console.Write( "Prop2='" + l_obj.Prop2 + "'; " );
Console.Write( "Prop3='" + l_obj.Prop3 + "'; " );
Console.WriteLine( "Prop4 = '" + l_obj.Prop4 + "'" );
}
Console.WriteLine( "Array2:" );
foreach ( var l_obj in l_objs2 )
{
Console.Write( "Prop1='" + l_obj.Prop1 + "'; " );
Console.Write( "Prop2='" + l_obj.Prop2 + "'; " );
Console.Write( "Prop3='" + l_obj.Prop3 + "'; " );
Console.WriteLine( "Prop4 = '" + l_obj.Prop4 + "'" );
}
Console.ReadKey( true );
}
}
<强>输出强>
Array1:
Prop1='Value A 1'; Prop2='Value A 3'; Prop3=''; Prop4 = 'Value A 2'
Prop1='Value A 4'; Prop2='Value A 6'; Prop3=''; Prop4 = 'Value A 5'
Prop1='Value A 7'; Prop2='Value A 9'; Prop3=''; Prop4 = 'Value A 8'
Array2:
Prop1='Value B 4'; Prop2='Value B 3'; Prop3='Value B 2'; Prop4 = 'Value B 1'
Prop1='Value B 8'; Prop2='Value B 7'; Prop3='Value B 6'; Prop4 = 'Value B 5'
Prop1='Value B 12'; Prop2='Value B 11'; Prop3='Value B 10'; Prop4 = 'Value B 9'
答案 2 :(得分:0)
using System;
class Test
{
public string P1 { get; set; }
public string P2 { get; set; }
}
class MainClass
{
static T MapArray<T>(double[] array, string propertyStartWith) where T: new()
{
T obj = new T();
Type t = typeof(T);
for (int i = 0; i < array.Length; i++)
{
var property = t.GetProperty(propertyStartWith + (i + 1).ToString());
property.SetValue(obj, Convert.ChangeType(array[i], property.PropertyType), null);
}
return obj;
}
public static void Main (string[] args)
{
double[] d = new double[] {
Math.PI, Math.E
};
Test t = MapArray<Test> (d, "P");
Console.WriteLine (t.P1);
Console.WriteLine (t.P2);
}
}
答案 3 :(得分:0)
这是一个没有错误检查的简单实现,但您可以指定自己的转换函数。目前它默认为Convert.ChangeType:
void Main()
{
var list = new List<double> { 1.0, 1.1, 2.2, 3.3 };
var instances = new List<A> { new A(), new A(), new A(), new A() };
ConvertZipMap(list, instances, item => item.P);
// 1
// 1
// 2
// 3
}
class A {
public int P { get; set; }
}
void ConvertZipMap<TSource,TTarget,TProperty>(
IEnumerable<TSource> source,
IEnumerable<TTarget> target,
Expression<Func<TTarget, TProperty>> propertySelector,
Func<TSource, TProperty> conversion = null) {
// create setter
var member = (MemberExpression)propertySelector.Body;
var param = Expression.Parameter(typeof(TProperty), "value");
var setExpr = Expression.Lambda<Action<TTarget, TProperty>>(
Expression.Assign(member, param),
propertySelector.Parameters[0],
param);
var set = setExpr.Compile();
// resolve conversion method
conversion = conversion ?? (x => (TProperty)Convert.ChangeType(x, typeof(TProperty)));
// convert -> zip -> map
foreach(var zip in source.Select(conversion).Zip(target, (value, item) => new { item, value })) {
set(zip.item, zip.value);
}
}
这个答案的关键部分是如何从getter表达式中create一个setter。