Добавление записей в результирующий набор с помощью оператора LINQ и вычисления

Предположим, что я вызываю конечную точку API и получаю некоторые обменные курсы в виде DataTable. Затем я фильтрую эти обменные курсы, используя инструкцию LINQ, чтобы возвращать только те курсы, которые меня интересуют.

LINQ для фильтрации обменных курсов:

var results = exchangeRates.Rows.Cast<DataRow>()
.Where(r => r.Field<double>("Rate") > 0)
.Where(r => r.Field<string>("FromCurrency").ToUpper() == "USD")
.Select(y => new
{
    FromCurrency = y.Field<string>("FromCurrency"),
    ToCurrency = y.Field<string>("ToCurrency"),
    ExchangeRate = y.Field<double>("Rate")
}).ToList();

Операция LINQ возвращает:

+------------------+----------------+---------+
| OriginalCurrency | TargetCurrency |   Rate  |
+------------------+----------------+---------+
|        USD       |       GBP      |  88.452 |
+------------------+----------------+---------+
|        USD       |       CAD      | 132.819 |
+------------------+----------------+---------+

Я хотел бы добавить к результирующим записям взаимные обменные курсы. Поэтому, если у меня обменный курс доллара США к фунту стерлингов 88,45, я хотел бы добавить запись для фунта стерлингов к доллару США 113,06. Так что в основном я меняю местами столбцы OriginalCurrency и TargetCurrency и беру обратное значение первой ставки, а затем умножаю на 10 000. У меня есть LINQ для фильтрации записей, но я не могу понять, как настроить оператор LINQ, чтобы добавить две новые записи о взаимном обменном курсе.

Желаемый результат оператора LINQ:

+------------------+----------------+--------+
| OriginalCurrency | TargetCurrency |  Rate  |
+------------------+----------------+--------+
|        USD       |       GBP      |  88.45 |
+------------------+----------------+--------+
|        USD       |       CAD      | 132.81 |
+------------------+----------------+--------+
|        GBP       |       USD      | 113.06 |
+------------------+----------------+--------+
|        CAD       |       USD      |  75.30 |
+------------------+----------------+--------+

person webworm    schedule 03.04.2020    source источник


Ответы (2)


Вы можете Select взаимные обменные курсы в новые перечисляемые первые

var reciprocalResults = results
    .Select(y => new
    {
        FromCurrency = y.ToCurrency,
        ToCurrency = y.FromCurrency ,
        ExchangeRate = Math.Round (10000 / y.ExchangeRate, 2)
    });

Затем Concat оба результата в новый список

var total = results.Concat(reciprocalResults).ToList();
person Pavel Anikhouski    schedule 03.04.2020
comment
Ты просто results = results.Concat(results.Select(...)) - person Magnus; 03.04.2020

Поскольку вы хотите сопоставить каждый элемент в последовательности с двумя элементами (скоростью и обратной величиной), вы должны использовать SelectMany.

Во-первых, напишите метод, который по строке в таблице возвращает 2 строки:

// Create a class called ExchangeRate, with the three properties in your anonymous object
private static IEnumerable<ExchangeRate> RateAndReciprocal(ExchangeRate rate) {
    yield return rate;
    yield return new ExchangeRate {
        FromCurrency = rate.ToCurrency,
        ToCurrency = rate.FromCurrency,
        ExchangeRate = 10000 / rate.ExchangeRate
    };
}

Затем вызовите SelectMany в конце цепочки методов:

.Select(y => new ExchangeRate
{
    FromCurrency = y.Field<string>("FromCurrency"),
    ToCurrency = y.Field<string>("ToCurrency"),
    ExchangeRate = y.Field<double>("Rate")
})
.SelectMany(RateAndReciprocal)
.ToList();

(Конечно, можно было сделать RateAndReciprocal встроенным, что избавило бы вас от создания класса ExchangeRate, но мне так больше нравится)

person Sweeper    schedule 03.04.2020
comment
Кажется, вы забыли про тогда умножьте на 10 000 :) - person Pavel Anikhouski; 03.04.2020
comment
@PavelAnikhouski Ой! Спасибо! - person Sweeper; 03.04.2020