Как выполнять арифметические операции над общими списками - PullRequest
0 голосов
/ 30 января 2019

У меня есть программа ac #, которая читает произвольные файлы CSV.Столбцы могут быть типа int, float или double.

В настоящее время я загружаю эти данные в список, есть ли способ выполнить основные арифметические операции между столбцами.Т.е. добавить две колонки.Если столбцы относятся к разным типам, я бы хотел следовать стандартному продвижению типов.

Есть ли простой способ добиться этого, если столбцы будут заключены в объект?

Вот пример кодаэто показывает поведение, которое я после.Мне нужно сохранить отдельные типы, из-за памяти и разрешения

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

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Основываясь на ответе Алексея, это решение, которое я придумал, основано на использовании динамического.

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
0 голосов
/ 30 января 2019

Нет поддержки общих арифметических операций , поэтому вам нужно выбрать что-то еще, что соответствует вашей цели.

Просто сделать все значения double одним вариантом и игнорировать нечисловые поля.Это упростит правила преобразования (ни к одному).

Другой выход - использовать dynamic для всех значений ( C # Добавление двух общих значений ).Это даст вам точные правила продвижения и возможность выполнять математические операции над любыми значениями (при условии, что значения на самом деле имеют правильный тип, а не только строки).Это, вероятно, то, что вам действительно нужно, если вы хотите скомпилировать правила (когда col[0] = col[1] + col[2] * col[3] является частью кода программы).

Если вы планируете анализировать выражения для столбцов, вы также можете добавить поддержку для продвижения значений.для более широких числовых типов как часть синтаксического анализатора.

...