简体   繁体   中英

Adding records to a result set via a LINQ statement and calculation

Assume that I am calling an API endpoint and getting back some exchange rates in the form of a DataTable. I then filter those exchange rates using a LINQ statement to return only those rates I am interested in.

LINQ for filtering exchange rates:

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 statement returns:

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

I would like to add, to the resultant records, the reciprocal exchange rates. So if I have an exchange rate of USD to GBP of 88.45 I would like to add a record for GBP to USD of 113.06. So basically I swap the OriginalCurrency and TargetCurrency columns and take the reciprocal of the first rate and then multiply by 10,000. I have the LINQ to filter the records but cannot figure out how to adjust the LINQ statement to add the two new reciprocal exchange rate records.

Desired LINQ statement return:

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

You can Select the reciprocal exchange rates into new enumerable first

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

Then Concat both results into new list

var total = results.Concat(reciprocalResults).ToList();

Since you want to map each item in the sequence into 2 items (the rate and the reciprocal), you should use SelectMany .

First, write a method that, given a row in the table, returns 2 rows:

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

Then, call SelectMany at the end of the method chain:

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

(Of course, you could have made RateAndReciprocal inline, which would have saved you from creating the ExchangeRate class, but I like this better)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM