Home > OS >  Iterate dictionary to make new dictionary with string values in them
Iterate dictionary to make new dictionary with string values in them

Time:10-01

I need to iterate dictionary and make new dictionary object from it. If the value of dictionary is integer then I want to populate keys and values into new dictionary object. Basically idea is make a new dictionary object which only contains keys and integer values. If there is any string values then I don't want to add those keys and values in it.

I tried like this but I wanted to see if there is any better way of doing this. I might be doing something wrong which is inaccurate so wanted to see if there is any better way.

public override object Save(IDictionary<string, object> value)
{
    IDictionary<string, object> newValues = new Dictionary<string, object>();
    foreach(var entry in value)
    {
        if (Int32.TryParse((string)entry.Value, out var id))
        {
            newValues.Add(entry.Key, id);
        }
    }
    return base.Process(newValues);
}

CodePudding user response:

Your approach is unsafe! This is because the cast to string may throw an exception. A better approach would be to check the type:

foreach(var i in dictionary) {

    if(i.Value is String str && int.TryParse(str, out int intValue)) {
       newValues.Add(i.Key, intValue);
    }
    else if (i.Value is int) {
       newValues.Add(i.Key, i.Value);
    }
}

You may add more control flows to also capture other kinds of numeric values such as doubles, decimals, floats, etc. followed by converting them to int.

You can change the order of the control flow for performance tuning.

CodePudding user response:

you can try this

 var id=0;
 IDictionary<string, int> newValues =value
   .Where(p => Int32.TryParse(p.Value.ToString(), out id))
   .ToDictionary(p => p.Key,
                 p => id
     );

or if you want object

var id=0;
 IDictionary<string, object> newValues =    myDictionary
   .Where(p => Int32.TryParse(p.Value.ToString(), out id))
   .ToDictionary(p => p.Key,
                 p => (object)id
    );
       
    

CodePudding user response:

I know you've had a bunch of answers.. but they're all so far either not quite there or not really an improvement on what you have (if you make the change mentioned in the comments..)

An alternative to what you have, using linq, would be:

Let's select every keyvaluepair and try and parse its value. If it parses, return an anonymous type that includes the Key and the parsed value, otherwise return null. Then let's exclude the nulls and turn it into a dictionary

 return base.Process(
   value.Select(kvp => int.TryParse(kvp.Value.ToString(), out var Val) ?  new { kvp.Key, Val } : null)
     .Where(x => x != null)
     .ToDictionary(x => x.Key, x => x.Val)
 );

But genuinely, it's effectively the same as what you have, except it's more compact but slower because it loops more.. and it's harder to understand.


If you're after literally just filtering the existing dictionary based on whether the entry's value is int flavored, but keeping it as-is:

 return base.Process(
   value
     .Where(kvp => kvp.Value is int || (kvp.Value is string s && int.TryParse(s, out var _)))
     .ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
 );

Another alternative could be to not prepare a new dictionary at all, but just remove bad values from the one you have

public override object Save(IDictionary<string, object> value)
{
    var toRemove = new List<string>(values.Count);
    foreach(var entry in value)
        if (entry.Value is string s && !int.TryParse(s, out var _))
            toRemove.Add(entry.Key);

    toRemove.ForEach(s => value.Remove(s));

    return base.Process(value);
}

CodePudding user response:

If you want a LINQ solution,

public override object Save(IDictionary<string, object> value)
{
    return base.Process(value.Where(v => int.TryParse(v.Value as string, out var _)));
}
  • Related