Home > front end >  C# Linq union multiple properties to one list
C# Linq union multiple properties to one list

Time:11-02

Basically I have an object with 2 different properties, both int and I want to get one list with all values from both properties. As of now I have a couple of linq queries to do this for me, but I am wondering if this could be simplified somehow -

var componentsWithDynamicApis = result
  .Components
  .Where(c => c.DynamicApiChoicesId.HasValue || 
              c.DynamicApiSubmissionsId.HasValue);

var choiceApis = componentsWithDynamicApis
  .Select(c => c.DynamicApiChoicesId.Value);

var submissionApis = componentsWithDynamicApis
  .Select(c => c.DynamicApiSubmissionsId.Value);

var dynamicApiIds = choiceApis
  .Union(submissionApis)
  .Distinct();

Not every component will have both Choices and Submissions.

CodePudding user response:

By simplify, I assume you want to combine into fewer statements. You can also simplify in terms of execution by reducing the number of times you iterate the collection (the current code does it 3 times).

One way is to use a generator function (assuming the type of items in your result.Components collection is Component):

IEnumerable<int> GetIds(IEnumerable<Component> components)
{
    foreach (var component in components)
    {
        if (component.DynamicApiChoicesId.HasValue) yield return component.DynamicApiChoicesId.Value;
        if (component.DynamicApiSubmissionsId.HasValue) yield return component.DynamicApiSubmissionsId.Value;
    }
}

Another option is to use SelectMany. The trick there is to create a temporary enumerable holding the appropriate values of DynamicApiChoicesId and DynamicApiSubmissionsId. I can't think of a one-liner for this, but here is one option:

var dynamicApiIds = result
    .Components
    .SelectMany(c => {
        var temp = new List<int>();
        if (c.DynamicApiChoicesId.HasValue) temp.Add(c.DynamicApiChoicesId.Value);
        if (c.DynamicApiSubmissionsId.HasValue) temp.Add(c.DynamicApiSubmissionsId.Value);
        return temp;
    })
    .Distinct();

@Eldar's answer gave me an idea for an improvement on option #2:

var dynamicApiIds = result
    .Components
    .SelectMany(c => new[] { c.DynamicApiChoicesId, c.DynamicApiSubmissionsId })
    .Where(c => c.HasValue)
    .Select(c => c.Value)
    .Distinct();

CodePudding user response:

To map each element in the source list onto more than one element on the destination list, you can use SelectMany.

var combined = componentsWithDynamicApis
    .SelectMany(x => new[] { x.DynamicApiChoicesId.Value, x.DynamicApiSubmissionsId.Value })
    .Distinct();

CodePudding user response:

I have not tested it but you can use SelectMany with filtering out the null values like below :

var componentsWithDynamicApis = result
  .Components
.Select(r=> new [] {r.DynamicApiChoicesId,r.DynamicApiSubmissionsId})
.SelectMany(r=> r.Where(p=> p!=null).Cast<int>()).Distinct();

CodePudding user response:

Similar to some of the other answers, but I think this covers all your bases with a very minimal amount of code.

var dynamicApiIds = result.Components
  .SelectMany(c => new[] { c.DynamicApiChoicesId, c.DynamicApiSubmissionsId}) // combine
  .OfType<int>() // remove nulls
  .Distinct();
  • Related