4

Assume that you have two IEnumerbale objects. How we can merge them (in some condition e.g merge in merge sort ...) and create a unique IEnumerable? I tried this with Zip, but in Zip the two list sizes should be equal (maybe you didn't get exception but maybe we have some data lost.)

In addition, I try it by using Enumerable.Range(...).Select(...) but i didn't get an acceptable result.

Furthermore, my question is totally different from using Union or this one, in fact as I said like merge in merge sort I like to preserve lists order (in fact just want to fill some gaps in first list).

It's easy to handle it with for loop, but i can't see any full linq way.

Edit:

Sample input:

lst1 = {5,10,12}
lst2 = {7,9,16,20,25}

result: {5,7,9,10,12,16,20,25}

this can be done with a for loop and two pointer in O(n + m) but I'm looking for linq solution in O(n+m)

for loop solution:

        var lst1 = new List<int> { 5, 10, 12 };
        var lst2 = new List<int> { 7, 9, 16, 20, 25 };

        var result = new List<int>();

        int j = 0;
        for (int i = 0; i < lst1.Count; i++)
        {
            while (j < lst2.Count && lst2[j] < lst1[i])
            {
                result.Add(lst2[j]);
                j++;
            }
            result.Add(lst1[i]);
        }

        while (j < lst2.Count)
        {
            result.Add(lst2[j]);
            j++;
        }
        Console.WriteLine(string.Join(",", result.ToArray()));
Community
  • 1
  • 1
Saeed Amiri
  • 22,252
  • 5
  • 45
  • 83
  • Please give some detail. I have no idea what you're looking for if `Union` won't work for you. – John Saunders Oct 10 '11 at 19:52
  • 2
    You can't do an OrderBy after your Union? – thekip Oct 10 '11 at 19:52
  • @John Saunders, assume most common problem, merge like merging in merge sort in this case if you use union again you should call OrderBy to have merge result, but it's not suitable in the mergesort case. – Saeed Amiri Oct 10 '11 at 19:54
  • @Anthony Pegram, No no, two list has a same type, see my prev comment. – Saeed Amiri Oct 10 '11 at 19:55
  • Again, why not `enumerable1.Union(enumerable2).OrderBy(whatever)`? – John Saunders Oct 10 '11 at 19:56
  • @thekip, exactly, because if I want do this i didn't do merge. – Saeed Amiri Oct 10 '11 at 19:57
  • @John Saunders, because of performance issue, I don't know other ways have good performance but this case causes to `log(n)` time slower, I want to see exactly is the case we can do it with for loops but linq prevent it? – Saeed Amiri Oct 10 '11 at 19:58
  • @Anthony Pegram, I'd edit it. – Saeed Amiri Oct 10 '11 at 20:03
  • @SaeedAmiri if you can do it with for loops, please show us. – Magnus Oct 10 '11 at 20:04
  • More detail, please. Are the two lists already in order? Is the second much smaller than the first? Approximately how many items are in the list? What kind of items are in the list? String or primitive type, or struct, or class? – John Saunders Oct 10 '11 at 20:09
  • @John Saunders, they are class but you assume they are `int`, and we don't know which one is bigger except checking in runtime. – Saeed Amiri Oct 10 '11 at 20:16
  • I have been benchmarking sorting using a top-down merge sort vs. Linq (vs. other things), and the merge sort and linq results have been coming out identicial. Why not just use Linq? – Steve Feb 18 '20 at 16:38
  • @Steve, I think you didn't understand the question. Merge sort is not the same as Merge operation. This question is old, at that time I asked it to understand computational power of linq. linq changed over a time of course, and I didn't work on it for a while, hence, I don't know if the answers here can be simplified or improved. – Saeed Amiri Feb 20 '20 at 15:00

3 Answers3

13

There is no such method in LINQ. And I don't think it's possible to combine the existing methods to do exactly what you want (if it was, it would be overly complicated).

But implementing such method yourself isn't that hard:

static IEnumerable<T> Merge<T>(this IEnumerable<T> first,
                               IEnumerable<T> second,
                               Func<T, T, bool> predicate)
{
    // validation ommited

    using (var firstEnumerator = first.GetEnumerator())
    using (var secondEnumerator = second.GetEnumerator())
    {
        bool firstCond = firstEnumerator.MoveNext();
        bool secondCond = secondEnumerator.MoveNext();

        while (firstCond && secondCond)
        {
            if (predicate(firstEnumerator.Current,  secondEnumerator.Current))
            {
                yield return firstEnumerator.Current;
                firstCond = firstEnumerator.MoveNext();
            }
            else
            {
                yield return secondEnumerator.Current;
                secondCond = secondEnumerator.MoveNext();
            }
        }

        while (firstCond)
        {
            yield return firstEnumerator.Current;
            firstCond = firstEnumerator.MoveNext();
        }

        while (secondCond)
        {
            yield return secondEnumerator.Current;
            secondCond = secondEnumerator.MoveNext();
        }
    }
}

And you could use it like this:

lst1.Merge(lst2, (i, j) => i < j)
svick
  • 236,525
  • 50
  • 385
  • 514
7

There is no Merge method in System.Linq.Enumerable. If you want one, you have to write it (with a for loop and a yield statement).

As with many "just by linq" questions - you should assume that every linq method is backed by some plain old .NET code that you could have written yourself.


Here's an untested freehand non-generic implementation

public static IEnumerable<int> Merge
(
this IEnumerable<int> source1,
IEnumerable<int> source2
)
{
  using(Enumerator<int> e1 = source1.GetEnumerator())
  {
    bool more1 = e1.MoveNext();
    using(Enumerator<int> e2 = source2.GetEnumerator()
    {
      bool more2 = e2.MoveNext();

      while (more1 && more2)
      {
        int v1 = e1.Current;
        int v2 = e2.Current;
        if (v1 < v2)
        {
          yield return v1;
          more1 = e1.MoveNext();
        }
        else
        {
          yield return v2;
          more2 = e2.MoveNext();
        }

      }
      while (more1 && ! more2)
      {
        yield return e1.Current;
        more1 = e1.MoveNext();
      }
      while (more2 && ! more1)
      {
        yield return e2.Current;
        more2 = e2.MoveNext();
      }
    }
  }
}
Amy B
  • 108,202
  • 21
  • 135
  • 185
-3

Use LINQ method Concat() http://msdn.microsoft.com/en-us/library/bb302894.aspx

Ilia G
  • 10,043
  • 2
  • 40
  • 59
  • This doesn't sort, but `var list3 = list1.Concat(list2).OrderBy(i => i);` does. – ChrisF Oct 10 '11 at 20:12
  • @SaeedAmiri I don't see anything that would mean Concat() isn't exactly what you need. If you want to sort it, then do that after... whats the problem? – Ilia G Oct 10 '11 at 20:23
  • @liho1eye, sort is log(n) time slower than normal merge. – Saeed Amiri Oct 10 '11 at 20:24
  • 1
    @SaeedAmiri: So? Have you measured the performance impact of `OrderBy()` verses your method? How much CPU time did you save? How do you know what sorting algorithm `OrderBy()` uses? Maybe it's already merge sort? Maybe it's even better? – Allon Guralnek Oct 10 '11 at 20:27
  • @SaeedAmiri your loop solution assumes that lists are already sorted, which means something have sorted them, right? – Ilia G Oct 10 '11 at 20:31
  • @Allon Guralnek, linq can't decide on input variation it just uses some sorting algorithms, all of them in worst case has at least O(nlogn) – Saeed Amiri Oct 10 '11 at 20:31
  • @liho1eye yes, when i'm talk about sorting in merge sort means two given lists are sorted before. – Saeed Amiri Oct 10 '11 at 20:32
  • yes that's it, and about downvote i didn't downvoted you but my first comment was to removing your answer to preventing from downvotes. – Saeed Amiri Oct 10 '11 at 20:39
  • @SaeedAmiri I am honestly not sure what are you saying. I also don't understand whay are you concerned about O() of sort. You gain nothing by making weak assumptions about the input data. You want to implement that function yourself? You can do that but in real world terms you are likely going to lose performance by using suboptimal/unoptimized code. Honestly just concat and order it. – Ilia G Oct 10 '11 at 20:46
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/4151/discussion-between-saeed-amiri-and-liho1eye) – Saeed Amiri Oct 10 '11 at 20:51