【问题标题】:How to perform arithmetic operations on generic lists如何对通用列表执行算术运算
【发布时间】:2019-01-29 22:19:21
【问题描述】:

我有一个读取任意 CSV 文件的 c# 程序。列的类型可以是 int、float 或 double。

我目前正在将此数据加载到列表中,有什么方法可以在列之间执行基本的算术运算。 IE。添加两列。如果列的类型不同,我想遵循标准类型提升。

有没有一种简单的方法来实现这一点,是否应该将列封装在一个对象中?

这是一个代码示例,显示了我所追求的行为。由于内存和资源的原因,我确实需要保留单独的类型

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
        }
    }
}

【问题讨论】:

  • 你尝试的时候发生了什么?您能否展示代码并具体描述您遇到的错误?
  • 我之前使用的是单一数据类型(存储在 List> 中),但是我需要处理的一些文件遇到了内存限制(已经加载了 15GB 的数据),以及精度限制。为了解决这个问题,我将主要使用整数和浮点数。
  • 像 Alexei 建议的那样使用 dynamic
  • but with some of the files I need to process ran into memory limitations 也许考虑使用yield returnIEnumerable 或流等,这样您就不会一次将文件的全部内容都保存在RAM中?
  • 我确实考虑过使用 IEnumerable,但在将其传递给绘图库之前我需要做一些分析。

标签: c# list generic-list


【解决方案1】:

不支持generic arithmetic operations,因此您必须选择适合您目标的其他内容。

只设置所有值double 是一种选择,忽略非数字字段。这将简化转换规则(无)。

另一种方法是对所有值使用dynamic (C# Adding two Generic Values)。它将为您提供遵循确切的提升规则和对任何值进行数学运算的能力(只要值实际上是正确的类型而不仅仅是字符串)。如果您正在考虑编译规则(当col[0] = col[1] + col[2] * col[3] 是程序代码的一部分时),那可能就是您真正想要的。

如果您打算解析列的表达式,您还可以添加对将值提升为更广泛的数字类型的支持作为解析器的一部分。

【讨论】:

  • 这足以帮助我回答我的问题,请参阅修改后的代码。
【解决方案2】:

根据 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-06
    • 1970-01-01
    • 2012-02-26
    • 2018-01-09
    相关资源
    最近更新 更多