如何对泛型列表执行算术运算
How to perform arithmetic operations on generic lists
我有一个 c# 程序可以读取任意 CSV 文件。列可以是 int、float 或 double 类型。
我目前正在将此数据加载到列表中,有什么方法可以在列之间执行基本算术运算。 IE。添加两列。如果列是不同类型,我想遵循标准类型提升。
是否有一种简单的方法可以实现这一点,是否应该将列封装在一个对象中?
这是一个代码示例,显示了我所追求的行为。由于内存和 res
,我确实需要保留不同的类型
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Example
{
class Program
{
static void Main(string[] args)
{
List<IList> data = new List<IList>();
data.Add(Enumerable.Range(0, 1000).ToList()); // Add a list of ints
data.Add(Enumerable.Range(0, 1000).Select(v=>(float)v).ToList()); // Add a list of floats
data.Add(Enumerable.Range(0, 1000).Select(v => (double)v).ToList()); // Add a list of doubles
data.Add(GenerateColumn(data[0], data[1], Operation.Add));
data.Add(GenerateColumn(data[1], data[2], Operation.Divide));
}
// This is what I would do if the lists were all the same type
static IList GenerateColumn(IList colA, IList colB,Operation operation)
{
List<double> result = null;
switch (operation)
{
case Operation.Add:
result = colA.Zip(colB, (a, b) => a + b).ToList();
break;
case Operation.Subtract:
result = colA.Zip(colB, (a, b) => a - b).ToList();
break;
case Operation.Multiply:
result = colA.Zip(colB, (a, b) => a * b).ToList();
break;
case Operation.Divide:
result = colA.Zip(colB, (a, b) => a / b).ToList();
break;
}
return result;
}
public enum Operation
{
Add,
Subtract,
Multiply,
Divide
}
}
}
不支持 generic arithmetic operations,因此您必须选择符合您目标的其他内容。
仅将所有值设置为 double
是一种选择,并忽略非数字字段。这将简化转换规则(到 none)。
另一种方法是对所有值 (C# Adding two Generic Values) 使用 dynamic
。它会让你遵循精确的提升规则和对任何值进行数学运算的能力(只要值实际上是正确的类型而不仅仅是字符串)。如果您正在考虑编译规则(当 col[0] = col[1] + col[2] * col[3]
是程序代码的一部分时),那可能就是您真正想要的。
如果您计划解析列的表达式,您还可以在解析器中添加对将值提升为更广泛的数字类型的支持。
根据 Alexei 的回答,这是我基于使用动态提出的解决方案。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Example
{
class Program
{
static void Main(string[] args)
{
List<List<dynamic>> data = new List<List<dynamic>>();
data.Add(new List<dynamic>());
data[0].AddRange(Enumerable.Range(0, 1000).Cast<dynamic>()); // Add a list of ints
data.Add(new List<dynamic>());
data[1].AddRange(Enumerable.Range(0, 1000).Select(v=>(float)v).Cast<dynamic>()); // Add a list of ints
data.Add(new List<dynamic>());
data[2].AddRange(Enumerable.Range(0, 1000).Select(v => (double)v).Cast<dynamic>()); // Add a list of ints
data.Add(GenerateColumn(data[0], data[0], Operation.Add)); // Result should be int column
data.Add(GenerateColumn(data[0], data[1], Operation.Subtract)); // Result should be float column
data.Add(GenerateColumn(data[1], data[2], Operation.Divide)); // Result should be double column
foreach (List<dynamic> lst in data)
{
Debug.WriteLine((Type)lst[0].GetType());
}
}
// This is what I would do if the lists were all the same type
static List<dynamic> GenerateColumn(List<dynamic> colA, List<dynamic> colB,Operation operation)
{
List<dynamic> result = null;
switch (operation)
{
case Operation.Add:
result = colA.Zip(colB, (a, b) => a + b).ToList();
break;
case Operation.Subtract:
result = colA.Zip(colB, (a, b) => a - b).ToList();
break;
case Operation.Multiply:
result = colA.Zip(colB, (a, b) => a * b).ToList();
break;
case Operation.Divide:
result = colA.Zip(colB, (a, b) => a / b).ToList();
break;
}
return result;
}
public enum Operation
{
Add,
Subtract,
Multiply,
Divide
}
}
}
输出是
System.Int32
System.Single
System.Double
System.Int32
System.Single
System.Double
我有一个 c# 程序可以读取任意 CSV 文件。列可以是 int、float 或 double 类型。
我目前正在将此数据加载到列表中,有什么方法可以在列之间执行基本算术运算。 IE。添加两列。如果列是不同类型,我想遵循标准类型提升。
是否有一种简单的方法可以实现这一点,是否应该将列封装在一个对象中?
这是一个代码示例,显示了我所追求的行为。由于内存和 res
,我确实需要保留不同的类型using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Example
{
class Program
{
static void Main(string[] args)
{
List<IList> data = new List<IList>();
data.Add(Enumerable.Range(0, 1000).ToList()); // Add a list of ints
data.Add(Enumerable.Range(0, 1000).Select(v=>(float)v).ToList()); // Add a list of floats
data.Add(Enumerable.Range(0, 1000).Select(v => (double)v).ToList()); // Add a list of doubles
data.Add(GenerateColumn(data[0], data[1], Operation.Add));
data.Add(GenerateColumn(data[1], data[2], Operation.Divide));
}
// This is what I would do if the lists were all the same type
static IList GenerateColumn(IList colA, IList colB,Operation operation)
{
List<double> result = null;
switch (operation)
{
case Operation.Add:
result = colA.Zip(colB, (a, b) => a + b).ToList();
break;
case Operation.Subtract:
result = colA.Zip(colB, (a, b) => a - b).ToList();
break;
case Operation.Multiply:
result = colA.Zip(colB, (a, b) => a * b).ToList();
break;
case Operation.Divide:
result = colA.Zip(colB, (a, b) => a / b).ToList();
break;
}
return result;
}
public enum Operation
{
Add,
Subtract,
Multiply,
Divide
}
}
}
不支持 generic arithmetic operations,因此您必须选择符合您目标的其他内容。
仅将所有值设置为 double
是一种选择,并忽略非数字字段。这将简化转换规则(到 none)。
另一种方法是对所有值 (C# Adding two Generic Values) 使用 dynamic
。它会让你遵循精确的提升规则和对任何值进行数学运算的能力(只要值实际上是正确的类型而不仅仅是字符串)。如果您正在考虑编译规则(当 col[0] = col[1] + col[2] * col[3]
是程序代码的一部分时),那可能就是您真正想要的。
如果您计划解析列的表达式,您还可以在解析器中添加对将值提升为更广泛的数字类型的支持。
根据 Alexei 的回答,这是我基于使用动态提出的解决方案。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Example
{
class Program
{
static void Main(string[] args)
{
List<List<dynamic>> data = new List<List<dynamic>>();
data.Add(new List<dynamic>());
data[0].AddRange(Enumerable.Range(0, 1000).Cast<dynamic>()); // Add a list of ints
data.Add(new List<dynamic>());
data[1].AddRange(Enumerable.Range(0, 1000).Select(v=>(float)v).Cast<dynamic>()); // Add a list of ints
data.Add(new List<dynamic>());
data[2].AddRange(Enumerable.Range(0, 1000).Select(v => (double)v).Cast<dynamic>()); // Add a list of ints
data.Add(GenerateColumn(data[0], data[0], Operation.Add)); // Result should be int column
data.Add(GenerateColumn(data[0], data[1], Operation.Subtract)); // Result should be float column
data.Add(GenerateColumn(data[1], data[2], Operation.Divide)); // Result should be double column
foreach (List<dynamic> lst in data)
{
Debug.WriteLine((Type)lst[0].GetType());
}
}
// This is what I would do if the lists were all the same type
static List<dynamic> GenerateColumn(List<dynamic> colA, List<dynamic> colB,Operation operation)
{
List<dynamic> result = null;
switch (operation)
{
case Operation.Add:
result = colA.Zip(colB, (a, b) => a + b).ToList();
break;
case Operation.Subtract:
result = colA.Zip(colB, (a, b) => a - b).ToList();
break;
case Operation.Multiply:
result = colA.Zip(colB, (a, b) => a * b).ToList();
break;
case Operation.Divide:
result = colA.Zip(colB, (a, b) => a / b).ToList();
break;
}
return result;
}
public enum Operation
{
Add,
Subtract,
Multiply,
Divide
}
}
}
输出是
System.Int32
System.Single
System.Double
System.Int32
System.Single
System.Double