Listing a field from all the entities in a collect

2019-08-05 09:24发布

问题:

I'm writing out an aggregated list of statuses. It works fine except for the situation where there are none. At the moment, null is rendered and the position is empty.

item.Stuff.Where(e => Condition(e))
  .Select(f => f.Status)
  .Aggregate("---", (a, b) => (a == "---") ? b : (a + b));

I've got a suggestion for solution and improvement as follows.

[Flags]
enum Status
{
    None = 0,
    Active = 1,
    Inactive = 2,
    Pending = 4,
    Deleted = 8
}

item.Stuff.Where(e => Condition(e))
  .Aggregate(Status.None, (a, b) => a | b.Status)

As I'm a great fan of simpler syntax, I love skipping the Select part. However, the result now is not all the elements listed. In fact, only a single one is listed (instead of five as previously) and None appears where there was a single status before.

Perhaps I'm too brain-stuck but I can't see why. And, consequently, not what I should do about it, neither... :(

回答1:

If the statuses are coming from an extenal system (i.e. a database) you might need to renumber the statuses there as well.

Note that this works only if you use power-of-two values as the values of the statuses.

Eg. if I use

[Flags]
enum Status
{
    None = 0,
    Active = 1,
    Inactive = 2,
    Pending = 3,
    Deleted = 4
}

then Status.Active | Status.Inactive will return Status.Pending (1+2=3).

Also, this way you only get a list of distinct used statuses, i.e. if you have 10 active and 5 pending items, you'll get Active, Pending as a result, without any frequency information.

If you need this information too, I would suggest doing some grouping, like:

string.Join(", ", item.Stuff.Where(e => Condition(e))
  .Select(f => f.Status)
  .GroupBy(status => status)
  .Select(group => string.Format("{0} {1}", group.Count(), group.Key));

this will result in "10 Active, 5 Pending" or an empty string if there are no groups.


EDIT: Now I think of it, string.Join might be a better solution to the original question as well (IEnumerable.Aggregate is a great method, but it might be an overkill). Just something like:

string.Join(", ", item.Stuff.Where(e => Condition(e)).Select(f => f.Status))