简体   繁体   中英

Checking valid combination of items in list

I have a list of items that I need to validate. The list can contain any number of items of the type A, B and C, but before the list can be saved, it must confirm to the following rules:

  1. If you have A, you need either B or C
  2. If you have B, you need A

I have ended up with the following code (saudo code):

bool IsListValid()
{
  var a = list.ContainsAny(A);
  var b = list.ContainsAny(B);
  var c = list.ContainsAny(C);

  if (!a && !b)
    return true;

  if (a && (b || c)
    return true;

  return false;
}

I don't like this code.
1. The use of Any three times in a row will potentially iterate the list three times
2. The if's doesn't look good to me.

Of cause it would be better with different variable names and by extracting the test into methods with good names, but I think there are better ways of solving this entirely. I'm just not sure how...

Any tips?

I would use a simple loop, it's both, comprehensible and efficient.

bool containsA = false, containsB = false, containsC = false;
for (int i = 0; i < list.Count; i++)
{
    Type itemType = list[i].GetType();
    if (!containsA) containsA = itemType == typeof(A);
    if (!containsB) containsB = itemType == typeof(B);
    if (!containsC) containsC = itemType == typeof(C);
    if (containsA && (containsB || containsC)) return true;
}
return (!containsA && !containsB);

If it's so important that you only go through the list once, you could do this:

bool a = false;
bool b = false;
bool c = false;
foreach(var x in list)
{
  if (x is A) a = true;
  if (x is B) b = true;
  if (x is C) c = true;
}

But I'd leave it as it is. If profiling later shows that this code is becoming a bottleneck, you can revisit it then.

As for the if's , that looks fine to me. As long as A, B and C are properly named (something like hasNotifyEmail or needsResponse , something that explains why you want them to work with the specified rules) then it should be easy for others to understand.

var hasA = list.Any(x => x.GetType() == typeof(A));
var hasB = list.Any(x => x.GetType() == typeof(B));
var hasC = list.Any(x => x.GetType() == typeof(C));

//If you have A, you need either B or C
// A AND (B xor C)
if (hasA && (hasB ^= hasC))
   return true;

//If you have B, you need A
if (hasB && hasA)
   return true;

   return false;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM