简体   繁体   中英

Lookup in LINQ to be based only on 1 column from joined collection

I have a Scrape collection with one of the columns being MPN code. I want to find a matching MPN code in one of few columns in Aws collection - however in Aws MPN can be found in MPN column, but it can alternatively appear in Model, ItemPartNumber etc. columns. Sometimes MPN is repeated in the same row in more than 1 column in Aws.

If I find the row with matching MPN in any columns, I want to stop searching this row and just take corresponding EAN from Aws. So ultimately the amount of rows in Scrape should not change after the query.

However with this query I get more rows, which looks like it finds matches on MPN then separately on ItemPartNumber, Model etc. and cumulates them.

How would I reformulate the query so I get Scrape with same amount of rows at at the start, enhanced with a EAN code from Aws?

public IEnumerable<Scrape> EnhanceWith(IEnumerable<Aws> awsData)
{
    IEnumerable<Scrape> query = from scr in scrapeData
                                from aws in awsData
                                where
                                (
                                    scr.MPN == aws.ItemPartNumber ||
                                    scr.MPN == aws.Model ||
                                    scr.MPN == aws.MPN ||
                                    scr.MPN == aws.PartNumber 
                                )
                                select
                                new Scrape
                                {
                                    EAN = aws.EAN,
                                    MPN = scr.MPN,
                                    Url = scr.Url,
                                };
    return query;
}

You don't need to join the collections, you can do a look up:

IEnumerable<Scrape> query = scrapeData.Select(scr => 
{
    scr.EAN= awsData.FirstOrDefault(aws => scr.MPN == aws.ItemPartNumber ||
                                           scr.MPN == aws.Model ||
                                           scr.MPN == aws.MPN ||
                                           scr.MPN == aws.PartNumber)?.EAN;
    return scr;
});
return query;

Try this:

var result =
    scrapeData
    .Select(scr => 
        new
        {
            SCR = scr,
            AWS = 
                awsData
                .FirstOrDefault(aws =>
                    scr.MPN == aws.ItemPartNumber ||
                    scr.MPN == aws.Model ||
                    scr.MPN == aws.MPN ||
                    scr.MPN == aws.PartNumber)
        })
    .Where(x => x.AWS != null)
    .Select(x => new Scrape
    {
        EAN = x.AWS.EAN,
        MPN = x.SCR.MPN,
        Url = x.SCR.Url,
    });

For each Scrape in scrapeData , we search for the first match in the awsData and we put the result in an anonymous object. Then we filter out the items where the matched Aws is null to remove the cases were a match was not found, and then for each item we create a new Scrape object with the required information from both the original Scrape object and the found Aws object.

If you want to include the cases where a match is not found, then simply remove the Where method call and check for null when you create the new Scrape objects like this:

    //.Where(x => x.AWS != null)
    .Select(x => new Scrape
    {
        EAN = x.AWS != null ? x.AWS.EAN : x.SCR.EAN,
        MPN = x.SCR.MPN,
        Url = x.SCR.Url,
    });

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