Kyu96
Kyu96

Reputation: 1349

Find missing required values in a List

Assume we are given two lists (could be any primitive type):

var arguments = new List<String>() {"a", "b", "c", "d", "e", "f", "g", "h"};
var required = new List<String>() {"c", "g"};

All values of the required list have to be in the arguments list. If none are missing return null, else return a List of the missing arguments. Oh and the required values can not occur multiple times, if that's the case an exception should be thrown.

This is what I managed to put together:

private static IList<string> FindMissingRequiredValues(List<string> required, List<string> arguments)
        {
            var missing = new List<string>();
            foreach (var r in required)
            {
                if (!arguments.Contains(r))
                    missing.Add(r);
            }

            if (missing.Count == 0)
                missing = null;
            return missing;
        }

It works but it doesn't take care of duplicates, and it looks ugly. Is there an elegant solution that is generic (works for any primitive type) and takes care of duplicates , maybe with linq?

Again for clarification, the following conditions should be met:

1) If the one (or more) of the required values occur multiple times in the arguments list, thrown an error. This only accounts for required values, other values can occur multiple times in the arguments list.

2) It should work for any primitive datatype

3) Return null if all required values occur exactly once in the arguments list.

4) If some required values are missing in the arguments list return a list of the missing ones.

Upvotes: 0

Views: 699

Answers (3)

Prasad Telkikar
Prasad Telkikar

Reputation: 16059

Here you want to check two conditions against lists.

  1. If all required list elements are present in list, then return null

  2. If there are any missing fields, then check missing list contains duplicate or not.

    • If there are any duplicates then throw an exception
    • Otherwise return list

Here you go with your logic

    // Except will give you list of elements from required list which are not present in arguments.
    var missing = required.Except(arguments); 

    // to return null we will check that missing list contains any value or not
    // if it is empty then retun null, which will satisfy your first condition
    if(!missing.Any()) 
        return null;
    else if(isDuplicate(arguments, required)) //Check for duplicates
         throw new Exception("Duplicate records");
    else
        return missing.Distinct().ToList(); //Else return distinct element from missing list.

As per your comment if you want to check duplicates in argument, then I added one extra function which will return boolean value

public static bool isDuplicate(List<string> arguments, List<string> required)
{
    var group = arguments.GroupBy( i => i );
    foreach( var grp in group )
    {
        if(required.Contains(grp.Key) && grp.Count() > 1)
            return true;
    }
    return false;
}

POC : .Net Fiddle

Upvotes: 2

Stas Ivanov
Stas Ivanov

Reputation: 1245

If you need a generic solution I would go with something like this:

static List<T> FindMissingRequiredElements<T>(List<T> required, List<T> arguments)
{
    // convert to Dictionary where we store the required item as a key against count for an item
    var requiredDict = required.ToDictionary(k => k, v => 0);

    foreach(var item in arguments)
    {
        if (requiredDict.ContainsKey(item)) // now we check each item in arguments
        {
            requiredDict[item]++; // if we have required, adding to count
            if (requiredDict[item] > 1) // if we met required item more than once, throw exception
            {
                throw new Exception($"Required item {item} appeared more than once!");
            }
        }
    }

    var result = new List<T>();
    // now we are checking for missing items
    foreach (var key in requiredDict.Keys)
    {
        if (requiredDict[key] == 0)
        {
            result.Add(key);
        }
    }

    return result.Any() // if there are missing items, return the list, if not - return null
        ? result
        : null;
}

The key idea here is to use Dictionary to count how many occurrences of required items we have in the list.

Upvotes: 1

Michał Turczyn
Michał Turczyn

Reputation: 37377

Try this

if(required.GroupBy(i => i).Any(g => g.Count > 1))
  throw new Exception("Duplicates found");
var missing = required.Except(arguments).ToList();
return missing.Lenght == 0 ? null : missing;

Upvotes: 1

Related Questions