-1

I am consuming an API that returns JSON that looks like this:

    {
        "lookup_table_data": [
            [
                {
                    "key": "id",
                    "value": 0
                },
                {
                    "key" : "label",
                    "value" : "something"
                }
            ],
            [
                {
                    "key": "id",
                    "value": 1
                },
                {
                    "key" : "label",
                    "value" : "something_else"
                }
            ]
       ]
  }

I made a class that I deserialize the json object into that looks like this:

public class LookupResponseModel
    {
        public Lookup_Table_Data[][] Lookup_table_data { get; set; }

        public class Lookup_Table_Data
        {
            public string Key { get; set; }
            public object Value { get; set; }
        }
    }      

Now imagine that the JSON response has over 1,000 records instead of the 2 that I gave in my example.

I am wanting to search through my model and be able to find where the value of the key "id" is equal to 1 - because I want to use the label key value of "something_else".

How would I be able to grab the label "something_else" with an id of 1 with this model?

Eldorian
  • 603
  • 1
  • 6
  • 18
  • 2
    Maybe this helps: [How can I deserialize JSON to a simple Dictionary in ASP.NET?](https://stackoverflow.com/questions/1207731/how-can-i-deserialize-json-to-a-simple-dictionarystring-string-in-asp-net). – Olivier Jacot-Descombes Apr 15 '19 at 23:14

4 Answers4

1

I would suggest an approach like this:

public class LookupResponseModel
{
    public Lookup_Table_Data[][] Lookup_table_data { get; set; }

    public class Lookup_Table_Data
    {
        public string Key { get; set; }
        public object Value { get; set; }
    }
}

// This will help compare the values and convert if necessary
// This part was missing from my original answer and made it not work
bool ObjectCompare(object a, object b)
{
    if (object.Equals(a, b))
    {
        return true;
    }
    else
    {
        var altB = Convert.ChangeType(b, Type.GetTypeCode(a.GetType()));
        return object.Equals(a, altB);
    }
}

// This will break the result up into an Array of Dictionaries
// that are easier to work with
Dictionary<string, object>[] MakeTables(LookupResponseModel lrm)
{
    return lrm.Lookup_table_data.Select( entry => entry.ToDictionary( e => e.Key, e => e.Value ) ).ToArray();
}

// This will help you find the dictionary that has the values you want
Dictionary<string, object> FindTable( Dictionary<string, object>[] tables, string key, object value )
{
    return tables.Where( dict => dict.TryGetValue(key, out object val) && ObjectCompare(value, val) ).FirstOrDefault(); 
}

// Here is how you might use them together
string GetLabel()
{
    var lrm = JsonConvert.DeserializeObject<LookupResponseModel>(json);
    var lookup = MakeTables(lrm);

    var table = FindTable( lookup, "id", 1 );

    return table["label"].ToString();  // Returns "something_else"
}
Darrin Cullop
  • 1,170
  • 8
  • 14
  • When I tried this method of doing things, on the FindTable method I end up getting an error that sequence contains no elements. – Eldorian Apr 16 '19 at 15:54
  • Yes, there was an issue in my original post. Just doing "==" won't match the objects because the JSON value comes back as Int64 but when you pass in the 1 value, it comes across as Int32, and the values are not equal. So, I wrote a new "ObjectCompare" function and call it from FindTable in place of the "==". it should work just fine now. – Darrin Cullop Apr 16 '19 at 16:53
1
var lookup = model.lookupTableData.Select(data => new { key = (long)data.First(kvp => kvp.Key == "id").Value, value = (string)data.First(kvp => kvp.Key == "label").Value).ToDictionary(kvp => kvp.key, kvp => kvp.value)
var displayText = lookup[1]; // "something_else"

My attempt from a phone, might not be 100% correct syntax.

ScottyD0nt
  • 348
  • 2
  • 8
  • You were very close on your syntax, just missing a } after the 2nd .Value. I ended up creating a method that returned a string and you passed in the id, the key of the value you wanted returned, and the model - and it worked perfectly for what I needed. Thank you! – Eldorian Apr 16 '19 at 16:26
0

The simple answer is, you say something like this

public class LookupResponseModel
{
  public LookupTableData[][] lookupTableData { get; set; }

  public class LookupTableData
  {
      public string Key { get; set; }
      public object Value { get; set; }
  }

  public LookupTableData[] FindById( int id )
  {
    if (this.lookupTableData == null) throw new InvalidOperationException();

    foreach ( LookupTableData[] entry in lookupTableData )
    {
      if (entry != null)
      {
        foreach( LookupTableData item in entry )
        {
          bool isMatch =  "id".Equals( item.Key ?? "", StringComparison.Ordinal )
                       && item.Value is int
                       && ((int)item.Value) == id
                       ;
          if ( isMatch )
          {
            return entry;
          }
        }
      }
    }
    return null;
  }

}
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
  • I think you're on the right track with this, but if I do a FindById on an Id in that Key Value pair it doesn't find it. I don't think it's searching on the correct level of the Array. Playing around with it now to see if I can find out why. – Eldorian Apr 15 '19 at 23:46
  • Ignore my earlier comment, I had something typed in wrong. The problem I'm now running into is if I do a FindById(1800) it's returning the object of the Id of 0 instead. – Eldorian Apr 15 '19 at 23:50
  • @Eldorian: updated that for you. Important to actually **check** the value of the field against the passed-in value, eh? – Nicholas Carey Apr 16 '19 at 00:50
0

Data :

LookupResponseModel model = new LookupResponseModel();

model.Lookup_table_data = new LookupResponseModel.Lookup_Table_Data[][]
{
    new LookupResponseModel.Lookup_Table_Data[]
    {
        new LookupResponseModel.Lookup_Table_Data(){Key = "id", Value = "0"},
        new LookupResponseModel.Lookup_Table_Data(){Key = "label", Value = "hello"},
        new LookupResponseModel.Lookup_Table_Data(){Key = "textbox", Value = "bye"}
    },
    new LookupResponseModel.Lookup_Table_Data[]
    {
        new LookupResponseModel.Lookup_Table_Data(){Key = "id", Value = "1"},
        new LookupResponseModel.Lookup_Table_Data(){Key = "label", Value = "banana"},
        new LookupResponseModel.Lookup_Table_Data(){Key = "textbox", Value = "potatoe"}
    },
    new LookupResponseModel.Lookup_Table_Data[]
    {
        new LookupResponseModel.Lookup_Table_Data(){Key = "id", Value = "2"},
        new LookupResponseModel.Lookup_Table_Data(){Key = "label", Value = "cat"},
        new LookupResponseModel.Lookup_Table_Data(){Key = "textbox", Value = "bydog"}
    }
};

This query gives us second set (all 3 Lookup_Table_Data where key is ID and value is 1) It still [][] and it can contain more than one result :

var _result = model.Lookup_table_data.Where(x => x.Any(y => y.Key == "id" && y.Value.Equals("1")));

And this one gives you exactly value of "label" key from previous set (Key = "label", Value = "banana") :

var _exactlyLabel = _result.Select(x => x.Where(y => y.Key == "label"));

Or you can make _result.SelectMany(... for [] not for [][]

Makarov2015
  • 139
  • 1
  • 6
  • When I tried this result comes back as Enumeration yielded no results. I think it's because it's searching through the 1st array and not the 2nd? – Eldorian Apr 16 '19 at 16:10