Home > Software design >  A way to glue two collection by equal properties in C#
A way to glue two collection by equal properties in C#

Time:10-10

It is any simple way to solve this task: I have two similar collection. Two collections have one type, but not the same number of elements. The second collection consists of the clients of the first, but not all. Example: Collection1 have 1-10 clientIds Collection2 have 1,5,8 clientIds. All clients from the first collection.

Like this:

collection1: ({ clientId = 1, propery1 = 1, property2 = null},
    { clientId = 2, property1 = 2, property2 = null})
collection2: ({ clientId = 1, propery1 = null, property2 = 1},
    { clientId = 2, property1 = null, property2 = 2})

I need to create a third collection like this:

collection3: ({ clientId = 1, propery1 = 1, property2 = 1},
    { clientId = 2, property1 = 2, property2 = 2})

So we take two items from different collection where clientId is equls. And filled other field.

I can do this like this way:

foreach (var item in collection1)
{
  item.property2 = collection2.First(x => x.clientId == item.clientId).property2
}

This way in not flexible. Also I feel that exist the easier way to solve this. Like using linq metod Zip or something else. Do you have any ideas? Thanks.

CodePudding user response:

Enumerable.Zip processes both arrays in order. If your collections have the same amount of elements and the same ClientIds you can use Zip. If not you can convert the second collection into a dictionary and then you can loop through the first collection.

    var collection1 = Enumerable.Range(0, 10).Select(r => new Elem{ClientId = r}).ToList();
    var collection2 = Enumerable.Range(0, 5).Select(r => new Elem{ClientId = r, AProperty = "Prop "   r}).ToList();
    var dic = collection2.ToDictionary(r => r.ClientId);

    collection1.ForEach(r =>
    {
        if (dic.TryGetValue(r.ClientId, out var elem))
            r.AProperty = dic[r.ClientId].AProperty;
    });
    
    collection1.Dump();

Fiddle

CodePudding user response:

You wrote:

So we take two items from different collection where clientId is equal. And filled other field.

So you only want Clients that have an Id that is in both collections. However, it is not clear to me which properties you want. In your example there is always a property with null value and one with non-null value. In that case you take the non-null value.

But what if both property values are null? And what if both are non-null?

To be able to select the properties you can use one of the overloads of Enumerable.Join To be able to specify the output, use the overload that has a property resultSelector.

IEnumerable<Client> collection1 = ...
IEnumerable<Client> collection2 = ...

// Join the two collections:
IEnumerable<Client> result = collection1.Join(collection2,

client => client.ClientId,  // from every Client in collection1 take the ClientId
client => client.ClientId,  // from every Client in collection2 take the ClientId

 // parameter resultSelector: when these values match, make one new Client:
(client1, client2) => new
{
    ClientId = client1.ClientId,

    // for Property1 take the non-null one, if there is one.
    // If both are null use null
    // If both are non-null use the one from client2 (which is in collection2)
    Property1 = (client2.Property1 == null) ? client1.Property1 : client2.Property1,

    // do the same for Property2
    Property2 = (client2.Property2 == null) ? client1.Property2 : client2.Property2,
});
  • If both client1.Property1 and client2.Property1 equal null, the result is null.
  • If client1.Property1 equals null and client2.Property1 not null, the result is client2.Property1
  • If client1.Property1 not null, and client2.Property1 equals null, the result is client1.Property1
  • If both client1.Property1 and client2.Property1 not null, the result is client1.Property1

If you want other values from the ones that were not specified in your example, change the code accordingly

  • Related