UnicornSnuggler
UnicornSnuggler

Reputation: 117

Merging Two Lists and Combining Object Values

I've done a lot of digging and I can't seem to find an answer to this particular problem; answers to similar problems, but nothing quite like this.

Essentially, what I'm trying to do is take two C# lists, both of which contain a range of C# Objects comprised of string-integer pairs, then merge them together, joining the values of similar Objects.

Let's say my Object Class looks like this;

public class Object
{
    public string Name;
    public int Value;
}

And we'll also say that my lists look like this;

    objectList1             objectList2
 Name        Value       Name        Value
Object1        1        Object1        1
Object2        1        Object2        1
Object3        1
Object4        1
Object5        1

My goal here is to combine the contents of objectList2's Objects to the corresponding Objects in objectList1. In this example, that would mean that objectList1 would look like this when all is said and done;

 Name        Value
Object1        2
Object2        2
Object3        1
Object4        1
Object5        1

Now I know this is possible to do with foreach and FindIndex() calls, but I'm almost positive there's a more efficient way to go about this. If I'm wrong, that's fine, but I'd like to know if I can optimize this because my gut tells me there has to be a simpler way.

Upvotes: 3

Views: 4693

Answers (3)

Greg
Greg

Reputation: 11480

I believe what you're looking to do:

var contents = sample.Concat(example).GroupBy(n => n.Name);

Basically it will create a grouping, but it will append the list together. Then group based on the name, which will provide a numeric indicator of how many of the same name exist. Basically, you end up with a IGrouping<Key, Value>.

For instance:

var merge = new List<Content>();
var contents = sample.Concat(example).GroupBy(n => n.Name);
foreach(var item in contents)
     merge.Add(new Content() { Name = item.Key, Value = item.Sum(value => value.Value) });

You could also, do it with all Linq if you wanted:

    var contents = example.Concat(sample)
        .GroupBy(n => n.Name)
        .SelectMany(content => 
                    content.Select((item, i) => new { Name = content.Key, Value = content.Sum(v => v.Value) }).Distinct());

Upvotes: 3

duloveme
duloveme

Reputation: 61

You can use LINQ as below

 var list1 = new List<Object>();
list1.Add(new Object { Name = "Object1", Value = 1 });
list1.Add(new Object { Name = "Object2", Value = 1 });
list1.Add(new Object { Name = "Object3", Value = 1 });
list1.Add(new Object { Name = "Object4", Value = 1 });
list1.Add(new Object { Name = "Object5", Value = 1 });
var list2 = new List<Object>();
list2.Add(new Object { Name = "Object1", Value = 1 });
list2.Add(new Object { Name = "Object2", Value = 1 });

var total = from item1 in list1
            join item2 in list2
            on item1.Name equals item2.Name into list3
            from subset in list3.DefaultIfEmpty()
            select new Object
            {
                Name = item1.Name,
                Value = item1.Value + (subset == null ? 0 : subset.Value)
            };

Upvotes: 1

Sean K
Sean K

Reputation: 794

Best bet I can think of is to use Dictionary, assuming all keys are unique

do a foreach on the smaller Dictionary (not shown below), checking for matching keys in the other, and then modifying if found or adding if not found (note this algorithm is destructive, make a copy to return if you want to preserve the originals)

    void Merge (Dictionary<string, int> a, Dictionary<string, int> b)
    {
        foreach (string key in a.Keys)
        {
            if (b.ContainsKey(key))
            {
                b[key] = b[key] + a[key];
            }
            else
            {
                b.Add(key, a[key]);
            }
        }
    }

Upvotes: 1

Related Questions