C# Lambda Expression for iterating through nested objects

Viewed 375

I have below JSON which I have de-serialized into a C# object and would like to extract the values of INFO_CARD_ID, DOCUMENT_NUM and REVISION_NM at each iteration.

{
    "result": {
        "message": "Successfully performed search",
        "columnlist": "INFO_CARD_ID,DOCUMENT_NUM,REVISION_NM,
        "recordcount": 2,
        "rows": [
            {
                "columns": [
                    {
                        "value": "UJ3P25HO3JBPLJZ2HU",
                        "key": "INFO_CARD_ID"
                    },
                    {
                        "value": "DOC1",
                        "key": "DOCUMENT_NUM"
                    },
                    {
                        "value": "05",
                        "key": "REVISION_NM"
                    }
                ]
            },
            {
                "columns": [
                    {
                        "value": "JWQ5TCIV4JC2BCQ4C5",
                        "key": "INFO_CARD_ID"
                    },
                    {
                        "value": "DOC2",
                        "key": "DOCUMENT_NUM"
                    },
                    {
                        "value": "05",
                        "key": "REVISION_NM"
                    }
                ]
            }
        ]
    }
}

Here are the C# classes:

    public class Columns
    {
        public string value { get; set; }
        public string key { get; set; }
    }

    public class Rows
    {
        public IList<Columns> columns { get; set; }
    }

    public class Result
    {
        public string message { get; set; }
        public string columnlist { get; set; }
        public int recordcount { get; set; }
        public IList<Rows> rows { get; set; }
    }

    public class searchOutputModel
    {
        public Result result { get; set; }
    }

So far, I have been trying to extract the information on a list with below expression but with no luck, as the individual value is getting stored on each iteration and not all the values at each iteration at the same time.

searchResponse = JsonConvert.DeserializeObject<searchOutputModel>(json);

var dynamicList = searchResponse.result.rows.SelectMany(x => x.columns).Where(y => y.key.Contains("INFO_CARD_ID") || y.key.Contains("DOCUMENT_NUM") || y.key.Contains("REVISION_NM")).Select(y => {
        dynamic myValue;
        if (y.key.Contains("INFO_CARD_ID"))
            myValue = new { INFO_CARD_ID = y.value };
        else if (y.key.Contains("DOCUMENT_NUM"))
            myValue = new { DOCUMENT_NUM = y.value };
        else
            myValue = new { REVISION_NM = y.value };
        return myValue;
    }).ToList();

Expected output:

INFO_CARD_ID       DOCUMENT_NUM  REVISION_NM
---------------------------------------------
UJ3P25HO3JBPLJZ2HU DOC1          05
JWQ5TCIV4JC2BCQ4C5 DOC2          05

I know I am doing wrong with iteration as it creates new list at each select, but I am not sure how can I achieve the solution that I am looking for. Any help is appreciated.

2 Answers

We just need to select one object per row, no need for SelectMany here. Each property can be gotten by using columns.FirstOrDefault.

I would advise you to create a proper class for this rather than using dynamic but it makes little difference to the logic below.

Not sure why you used Contains on the column.key check, I've used ==

var dynamicList = searchResponse.result.rows.Select(r => 
    new {
        INFO_CARD_ID = r.columns.FirstOrDefault(c => c.key == "INFO_CARD_ID")?.value,
        DOCUMENT_NUM = r.columns.FirstOrDefault(c => c.key == "DOCUMENT_NUM")?.value,
        REVISION_NM = r.columns.FirstOrDefault(c => c.key == "REVISION_NM")?.value,
    }).ToList();

If you convert each Rows object to a Dictionary, you can use the Dictionary to create objects:

var ans = searchResponse.result.rows
            .Select(r => r.columns.ToDictionary(c => c.key, c => c.value))
            .Select(cd => new {
                INFO_CARD_ID = cd["INFO_CARD_ID"],
                DOCUMENT_NUM = cd["DOCUMENT_NUM"],
                REVISION_NM = cd["REVISION_NM"]
            });
Related