Merge array of objects into a single one based on item values in C#

78 Views Asked by At

I need to merge an array of objects into a single one, based on the items values The idea is more or less like this: I have this C# method

private SecurityResponse mergeSecuritySettings(SecurityResponse[] profileDetails)
{
// return merged object
}

in which SecurityResponse[] is an array of security profiles, each one with his own security settings for each item on the array e.g.:

[
  {
    "colorSettings": [
      {
        "settingKey": "A_288",
        "securitySettingValue": "R"
      },
      {
        "settingKey": "A_288_556",
        "securitySettingValue": "R"
      }
    ],
    "speedSettings": [
      {
        "settingKey": "L_19",
        "securitySettingValue": "R"
      },
      {
        "settingKey": "L_19_38",
        "securitySettingValue": "H"
      }
    ],
    "shapeSettings": [
      {
        "settingKey": "P_8",
        "securitySettingValue": "W"
      },
      {
        "settingKey": "P_8_8",
        "securitySettingValue": "W"
      }
    ],
    "brandSettings": [
      {
        "settingKey": "R_340",
        "securitySettingValue": "R"
      },
      {
        "settingKey": "R_337",
        "securitySettingValue": "H"
      }
    ]
  },
  {
  "colorSettings": [
    {
      "settingKey": "A_288",
      "securitySettingValue": "W"
    },
    {
      "settingKey": "A_288_556",
      "securitySettingValue": "W"
    }
  ],
  "speedSettings": [
    {
      "settingKey": "L_19",
      "securitySettingValue": "R"
    },
    {
      "settingKey": "L_19_38",
      "securitySettingValue": "W"
    }
  ],
  "shapeSettings": [
    {
      "settingKey": "P_8",
      "securitySettingValue": "W"
    },
    {
      "settingKey": "P_8_8",
      "securitySettingValue": "W"
    }
  ],
  "brandSettings": [
    {
      "settingKey": "R_340",
      "securitySettingValue": "R"
    },
    {
      "settingKey": "R_337",
      "securitySettingValue": "R"
    }
  ]
}
]

the key here is the "securitySettingValue" (W = Write, R = Read, H = Hide) , and the output criteria should be from the most... up to the less permissive (notice in each item there is a unique settingKey that will repeat on each element of the "SecurityResponse" array),

so... for he input data from above, the output should be:

{
  "colorSettings": [
    {
      "settingKey": "A_288",
      "securitySettingValue": "W"
    },
    {
      "settingKey": "A_288_556",
      "securitySettingValue": "W"
    }
  ],
  "speedSettings": [
    {
      "settingKey": "L_19",
      "securitySettingValue": "R"
    },
    {
      "settingKey": "L_19_38",
      "securitySettingValue": "W"
    }
  ],
  "shapeSettings": [
    {
      "settingKey": "P_8",
      "securitySettingValue": "W"
    },
    {
      "settingKey": "P_8_8",
      "securitySettingValue": "W"
    }
  ],
  "brandSettings": [
    {
      "settingKey": "R_340",
      "securitySettingValue": "R"
    },
    {
      "settingKey": "R_337",
      "securitySettingValue": "R"
    }
  ]
}

Maybe the solution is simple, but I'm not seeing it without entering in several nested loops, (mainly because of my lack of knowledge in C#).

Any suggestion on how to approach this one ?, are there built in methods for this ?

Thanks in advance!

2

There are 2 best solutions below

2
Ihdina On

Try like this:

Use Serialize JSON and Deserialize JSON, look at https://www.newtonsoft.com/json

using System;
using System.Collections.Generic;
using Newtonsoft.Json;

public class Program
{
    public class BrandSetting
    {
        public string settingKey { get; set; }
        public string securitySettingValue { get; set; }
    }

    public class ColorSetting
    {
        public string settingKey { get; set; }
        public string securitySettingValue { get; set; }
    }

    public class ShapeSetting
    {
        public string settingKey { get; set; }
        public string securitySettingValue { get; set; }
    }

    public class SpeedSetting
    {
        public string settingKey { get; set; }
        public string securitySettingValue { get; set; }
    }

    public class Root
    {
        public List<BrandSetting> brandSettings { get; set; }
        public List<ColorSetting> colorSettings { get; set; }
        public List<ShapeSetting> shapeSettings { get; set; }
        public List<SpeedSetting> speedSettings { get; set; }
    }

    public static void Main()
    {       
        /*
        // JSON Serialize
        Root root = new Root();
        
        root.brandSettings = new List<BrandSetting>();
        BrandSetting brandSetting = new BrandSetting(){
            settingKey = "1",
            securitySettingValue = "2"      
        };
        root.brandSettings.Add(brandSetting);

        root.colorSettings = new List<ColorSetting>();
        ColorSetting colorSetting = new ColorSetting(){
            settingKey = "1",
            securitySettingValue = "2"      
        };
        root.colorSettings.Add(colorSetting);

        root.shapeSettings = new List<ShapeSetting>();
        ShapeSetting shapeSetting = new ShapeSetting(){
            settingKey = "5",
            securitySettingValue = "6"      
        };
        root.shapeSettings.Add(shapeSetting);

        root.speedSettings = new List<SpeedSetting>();
        SpeedSetting speedSetting = new SpeedSetting(){
            settingKey = "7",
            securitySettingValue = "8"      
        };
        root.speedSettings.Add(speedSetting);

        string json = JsonConvert.SerializeObject(root);        
        json = "[" + json.Replace('\"', '\'') + "]";
        Console.WriteLine(json);
        Console.WriteLine("");
        */
        
        // json example
        String json = @"[{'colorSettings':[{'settingKey':'A_288','securitySettingValue':'R'},{'settingKey':'A_288_556','securitySettingValue':'R'}],'speedSettings':[{'settingKey':'L_19','securitySettingValue':'R'},{'settingKey':'L_19_38','securitySettingValue':'H'}],'shapeSettings':[{'settingKey':'P_8','securitySettingValue':'W'},{'settingKey':'P_8_8','securitySettingValue':'W'}],'brandSettings':[{'settingKey':'R_340','securitySettingValue':'R'},{'settingKey':'R_337','securitySettingValue':'H'}]},{'colorSettings':[{'settingKey':'A_288','securitySettingValue':'W'},{'settingKey':'A_288_556','securitySettingValue':'W'}],'speedSettings':[{'settingKey':'L_19','securitySettingValue':'R'},{'settingKey':'L_19_38','securitySettingValue':'W'}],'shapeSettings':[{'settingKey':'P_8','securitySettingValue':'W'},{'settingKey':'P_8_8','securitySettingValue':'W'}],'brandSettings':[{'settingKey':'R_340','securitySettingValue':'R'},{'settingKey':'R_337','securitySettingValue':'R'}]}]";

        // JSON Deserialize
        List<Root> SecurityResponses = JsonConvert.DeserializeObject<List<Root>>(json);
        //
        /*
        foreach (Root ro in SecurityResponses)
        {
            if(ro is null) {
                continue;
            }
            //
            foreach (BrandSetting bs in ro.brandSettings)
            {
                if(bs is null) {
                    continue;
                }
                Console.WriteLine("BrandSetting Key: " + bs.settingKey + " BrandSetting Value" + bs.securitySettingValue);          
            }
        }
        
        foreach (Root ro in SecurityResponses)
        {
            if(ro is null) {
                continue;
            }
            foreach (ColorSetting cs in ro.colorSettings)
            {
                if(cs is null) {
                    continue;
                }
                Console.WriteLine("ColorSetting Key: " + cs.settingKey + " ColorSetting Value" + cs.securitySettingValue);          
            }
        }

        foreach (Root ro in SecurityResponses)
        {
            if(ro is null) {
                continue;
            }
            foreach (ShapeSetting ss in ro.shapeSettings)
            {
                if(ss is null) {
                    continue;
                }
                Console.WriteLine("ShapeSetting Key: " + ss.settingKey + " ShapeSetting Value" + ss.securitySettingValue);          
            }
        }

        foreach (Root ro in SecurityResponses)
        {
            if(ro is null) {
                continue;
            }
            foreach (SpeedSetting spe in ro.speedSettings)
            {
                if(spe is null) {
                    continue;
                }
                Console.WriteLine("SpeedSetting Key: " + spe.settingKey + " SpeedSetting Value" + spe.securitySettingValue);            
            }
        }
        */
        
        Console.WriteLine("Find \'R\' in SecurityResponses/*/securitySettingValue");
        
        List<Root> roResult = new List<Root>();
        foreach(var sr in SecurityResponses)
        {
            foreach(var bs in sr.brandSettings)
            {
                if(bs.securitySettingValue == "R") 
                {
                    Root ro = new Root();
                    ro.brandSettings = new List<BrandSetting>();
                    ro.brandSettings.Add(bs);
                    roResult.Add(ro);
                }
            }

            foreach(var cs in sr.colorSettings)
            {
                if(cs.securitySettingValue == "R") 
                {
                    Root ro = new Root();
                    ro.colorSettings = new List<ColorSetting>();
                    ro.colorSettings.Add(cs);
                    roResult.Add(ro);
                }
            }
            
            foreach(var ss in sr.shapeSettings)
            {
                if(ss.securitySettingValue == "R") 
                {
                    Root ro = new Root();
                    ro.shapeSettings = new List<ShapeSetting>();
                    ro.shapeSettings.Add(ss);
                    roResult.Add(ro);
                }
            }

            foreach(var sps in sr.speedSettings)
            {
                if(sps.securitySettingValue == "R") 
                {
                    Root ro = new Root();
                    ro.speedSettings = new List<SpeedSetting>();
                    ro.speedSettings.Add(sps);
                    roResult.Add(ro);
                }
            }

        }
        
        // print result
        foreach (Root ro in roResult)
        {
            if(ro is null) { continue;}
            
            if(ro.brandSettings is not null) {              
                foreach(var bs in ro.brandSettings)
                {
                    if(bs is null) { continue; }
                    Console.WriteLine("BrandSetting Key: " + bs.settingKey + " BrandSetting Value: " + bs.securitySettingValue);            
                }
            }
            
            if(ro.colorSettings is not null) {              
                foreach(var cs in ro.colorSettings)
                {
                    if(cs is null) { continue; }
                    Console.WriteLine("ColorSetting Key: " + cs.settingKey + " ColorSetting Value: " + cs.securitySettingValue);            
                }
            }

            if(ro.shapeSettings is not null) {          
                foreach(var ss in ro.shapeSettings)
                {
                    if(ss is null) { continue; }
                    Console.WriteLine("ShapeSetting Key: " + ss.settingKey + " ShapeSetting Value: " + ss.securitySettingValue);            
                }
            }

            if(ro.speedSettings is not null) {          
                foreach(var sps in ro.speedSettings)
                {
                    if(sps is null) { continue; }
                    Console.WriteLine("SpeedSetting Key: " + sps.settingKey + " SpeedSetting Value: " + sps.securitySettingValue);          
                }
            }
        }

    }
}

Result:

Find 'R' in SecurityResponses/*/securitySettingValue
BrandSetting Key: R_340 BrandSetting Value: R
ColorSetting Key: A_288 ColorSetting Value: R
ColorSetting Key: A_288_556 ColorSetting Value: R
SpeedSetting Key: L_19 SpeedSetting Value: R
BrandSetting Key: R_340 BrandSetting Value: R
BrandSetting Key: R_337 BrandSetting Value: R
SpeedSetting Key: L_19 SpeedSetting Value: R
0
Franco Aguilera On

I think I found a solution for this one (I apologize in advance if I don't express myself correctly, as I said before C# is not my biggest strength):

public class ItemSetting
{
    public string settingKey { get; set; }
    public string securitySettingValue { get; set; }
}

public enum SettingValueEnum
{
    [System.Runtime.Serialization.EnumMember(Value = @"H")]
    Hide = 0,
    [System.Runtime.Serialization.EnumMember(Value = @"R")]
    ReadOnly = 1,
    [System.Runtime.Serialization.EnumMember(Value = @"W")]
    Write = 2,
}

private SecurityResponse mergeSecuritySettings(SecurityResponse[] profileDetails)
{
    // create an empty object as a placeholder
    var mergedSettings = new SecurityResponse() {};
    // get all the SecurityResponse keys
    var roleDetailKeys = typeof(SecurityResponse).GetProperties();

    foreach (var key in roleDetailKeys)
    {
        // I'll group all the arrays under the same key into a single one
        var mergedList = profileDetails.SelectMany(role => (ICollection<ItemSetting>)key.GetValue(role)).ToList();
        
        // since now I have items with the key repeated, I can group them, and make the filter there
        var groupedBySettingKey = mergedList.GroupBy(item => item.settingKey).ToDictionary(group => group.Key, group => group.ToList());
        var filteredDictionary = groupedBySettingKey.ToDictionary(
            kvp => kvp.Key,
            kvp => kvp.Value.FirstOrDefault(item => item.SecuritySettingValue == SettingValueEnum.Write || item.SecuritySettingValue == SettingValueEnum.ReadOnly) 
        );

        // add the result array items, under the key of the initial placeholder
        key.SetValue(mergedSettings, filteredDictionary.Values.ToArray());
    }

    return mergedSettings;
}