-2

I have list of object array (List<object[]> a) that come from different sources (files, sql, webservices) and I need a way to join them. For example, I have this two list:

        List<object[]> listA = new List<object[]>();
        object[] a = new object[] { 1, "A", 1200, "2016-12-31" };
        listA.Add(a);
        a = new object[] { 2, "B", 5200, "2016-12-31" };
        listA.Add(a);
        a = new object[] { 3, "C", 3500, "2016-12-31" };
        listA.Add(a);
        a = new object[] { 4, "D", 100, "2016-12-31" };
        listA.Add(a);

        List<object[]> listB = new List<object[]>();
        object[] b = new object[] { 44,  859, "2016-12-08" };
        listB.Add(b);
        b = new object[] { 23, 851, "2016-12-07" };
        listB.Add(b);
        b = new object[] { 31, 785, "2016-12-09" };
        listB.Add(b);

And the result will be this one:

        List<object[]> listC = new List<object[]>();
        object[] c = new object[] { 1, "A", 1200+859, 44, "2016-12-08" };
        listC.Add(c);
        c = new object[] { 2, "B", 5200+851, 23,  "2016-12-07" };
        listC.Add(c);
        c = new object[] { 3, "C", 3500+785, 31, "2016-12-09" };
        listC.Add(c);
        c = new object[] { 4, "D", 100, null, null };
        listC.Add(c);

The lists are bigger than in the example and I have to configure how to merge then but if I found a way to do this in linq is the half of the way. Any ideas?

koes
  • 1
  • 2
  • 1
    Mind telling us the pattern that you have to follow? – Ian H. Feb 13 '17 at 12:34
  • http://stackoverflow.com/questions/4488054/merge-two-or-more-lists-into-one-in-c-sharp-net – Sachin Feb 13 '17 at 12:34
  • @IanH. The pattern ist [A, B, C] + [D, E, F] = [A, B, C+D, E, F]. First array from `listA` and second array from `listB` – Camo Feb 13 '17 at 12:36
  • 5
    C# is language with a very strict, static and advanced type system. Why are all these values stored as `object` in arrays. What keeps you from designing nice types for your business data? That would surely also make merging them easier. Plus we would understand _what_ your are trying to merge _how_ here. – René Vogt Feb 13 '17 at 12:36
  • 2
    What @RenéVogt said. Really. Use classes, not object arrays to store your data. This code looks horrible. – spender Feb 13 '17 at 12:38
  • 1
    @Camo Using your notation, do you rather mean `[A,B,C,]+[D,E,F] = [A+D,B+E,C+F]`? – Codor Feb 13 '17 at 12:38
  • You might want to clarify what rules you are using to do this merge. You seem to be matching the first item of each list, the second item of each list, etc. but given the lists are differing lengths there clearly doesn't seem to be a one to one mapping so this strategy seems a little odd. On the other hand if it is just merging them in order then this seems like a pretty simple operation leading me to ask where exactly you are having problems? Is it that you aren't sure how to iterate two lists simultaneously or something else? – Chris Feb 13 '17 at 12:38
  • @Codor No. But I need to correct my pattern: [A, B, C] + [D, E, F] = [A, B, C+E, D, F] – Camo Feb 13 '17 at 12:41
  • It is [A, B, C, G] + [D, E, F] = [A, B, C+E, D, F]. But it is based on some configuration the user writes. This is only an example. The usuer could group by the data too and do other operations with data. I can use classes because it come from other sources and I don't know the structure – koes Feb 13 '17 at 14:37

1 Answers1

2

You can zip both sequences and concat with left items from listA:

listA.Zip(listB, (a, b) => 
         new object[] { a[0], a[1], (int)a[2] + (int)b[1], b[0], b[2] })
     .Concat(listA.Skip(listB.Count).Select(a => 
         new object[] { a[0], a[1], a[2], null, null }))

You can also use group join or select items from second list by index of item in first list.


I also suggest you to use custom classes instead of arrays of objects to make your code more readable, get nice type checking, descriptive properties, and intellisense. E.g.

public class Foo
{
   public int Id { get; set; }
   public string Name { get; set; }
   public int Value { get; set; }
   public DateTime Date { get; set; }
}

And

public class Bar
{
   public int Id { get; set; }
   public int Value { get; set; }
   public DateTime Date { get; set; }
}

Of course you should use more appropriate names here. Now your code will look like

List<Foo> foos = new List<Foo> {
   new Foo { Id=1, Name="A", Value=1200, Date=new DateTime(2016,12,31) },
   new Foo { Id=2, Name="B", Value=5200, Date=new DateTime(2016,12,31) },
   new Foo { Id=3, Name="C", Value=3500, Date=new DateTime(2016,12,31) },
   new Foo { Id=4, Name="D", Value=100, Date=new DateTime(2016,12,31) },
};

List<Bar> bars = new List<Bar> {
   new Bar { Id=44, Value=859, Date=new DateTime(2016,12,8) },
   new Bar { Id=23, Value=851, Date=new DateTime(2016,12,7) },
   new Bar { Id=31, Value=785, Date=new DateTime(2016,12,9) }
};

You can also create custom type to hold combined data.

public class Result
{
    public int FooId {get; set; }
    public string Name {get; set; }
    public int Value {get;set;}
    public int? BarId {get;set;}
    public DateTime? Date {get; set;}
}

And getting results will look like

var results = foos.Zip(bars, (f, b) => new Result{ 
    FooId = f.Id, Name = f.Name, Value = f.Value + b.Value, BarId =  b.Id, Date = b.Date
}).Concat(foos.Skip(bars.Count).Select(f => new Result {
    FooId = f.Id, Name = f.Name, Value = f.Value
}));

Try Working Code

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • 1
    I can't see how the desired output correlates to the zipping of the two source lists. – spender Feb 13 '17 at 12:38
  • 1
    ...actually, yes I do. Ignore me. – spender Feb 13 '17 at 12:39
  • That's a great solution, I wasn't aware of Zip – peval27 Feb 13 '17 at 12:41
  • in your Foo/Bar example, I'd use DateTime? instead. – peval27 Feb 13 '17 at 12:42
  • Thanks, but I can use custom classes because is data that come from different sources (bdd, web services) in that way and I don't know the structure before. I have another class that explain me what is arriving in that object[] and the way I have to merge both – koes Feb 13 '17 at 14:32
  • @koes you know data structure before. Otherwise why do you think that second item in listA array contains string? And why addition of third item from a with second item from b should work? How do you know that there are numbers and numbers which you should sum? – Sergey Berezovskiy Feb 13 '17 at 14:36
  • @Sergey Berezovskiy in my app there are other objects that explain how the data come in that object array, basically the index in the array and the type. In other I have the metadata to merge both and how to calculate the new colum sum of data from both lists. – koes Feb 13 '17 at 14:41
  • @koes combine object which explain how the data come in that object array with item in object array and you'll get custom class – Sergey Berezovskiy Feb 13 '17 at 14:50
  • @Sergey Berezovskiy can you explain? I have the List and a TypeEnum[] – koes Feb 13 '17 at 14:55
  • @koes probably you should post your code to codreview.stackexchange – Sergey Berezovskiy Feb 13 '17 at 15:15