3

I have been searching for a while in the internet yet cant find what i really needed. My problem is that I have two linq statements which I am planning to have them in UNION so that they'll be mergen into 1 single set of list but I want to removed those duplicate values. To be specific here is the a scenario:

query 1 = "this is a test","Yes", "This is a remark"
          "this is a test2","No", "This is the second remark"

query 2 = "this is a test","",""
          "this is a test2","",""
          "this is a test3","",""
          "this is a test4","",""

now what I want to happen is something like this:

          "this is a test","Yes", "This is a remark"
          "this is a test2","No", "This is the second remark",
          "this is a test3","",""
          "this is a test4","",""

How can I do this in LINQ?thanks in advance!

Soroush Mirzaei
  • 936
  • 2
  • 19
  • 34
Clyde
  • 732
  • 8
  • 19

3 Answers3

4

You could use the following query:

var result = from item in query2
             let match = query1.SingleOrDefault (e => e[0] == item[0])
             select match ?? item;

This will iterate over query2, and for each item it uses SingleOrDefault to find the item in query1 where the first elements of the items match, or null. Then the select yields either the item called match from query1, if it is not null, or the current item of query2.


Another, probably faster approach is to create an appropriate IEqualityComparer and using Union, like this:

class FirstElementComparer : IEqualityComparer<string[]>
{
    //TODO error checking
    public bool Equals(string[] a, string[] b)
    {       
        return a[0].Equals(b[0]);
    }

    public Int32 GetHashCode(string[] obj)
    {
        return obj[0].GetHashCode();
    }
}

and use it like this:

void Main()
{
    string[][] query1 = {new [] {"this is a test","Yes", "This is a remark"},
                         new [] {"this is a test2","No", "This is the second remark"}};

    string[][] query2 = {new [] {"this is a test","",""},
                         new [] {"this is a test2","",""},
                         new [] {"this is a test3","",""},
                         new [] {"this is a test4","",""}};

    query1.Union(query2, new FirstElementComparer()).Dump();                         
}

The EqualityComparer is used by Union to compare the elements in query1 with the elements in query2. It does so by just comparing the first item in each array.


Result:

enter image description here

sloth
  • 99,095
  • 21
  • 171
  • 219
  • HI sir!this has solved the problem.. can you explain this to me sir??? Thanks a lot!im new to linq – Clyde May 08 '13 at 09:41
  • @VincentClyde I added some explanations. – sloth May 08 '13 at 09:46
  • Won't work when there are items in query1 not present in query2. – Serge May 08 '13 at 09:53
  • @Serge True for the first solution, but OP said that this is ever the case (in a deleted comment). – sloth May 08 '13 at 09:58
  • @Dominic, what's "Dump"? Is it part of System.Linq? – Serge May 08 '13 at 10:17
  • 1
    @Serge No, it's an extension method provided by [linqpad](https://www.linqpad.net) to print any object, as you see in the image. If you don't know linqpad, you really should give it a try :-) – sloth May 08 '13 at 11:24
3

Something like this...

query1.Union(query2).GroupBy(q => q[0]).Select(grp => grp.FirstOrDefault());

(not tested)

Serge
  • 6,554
  • 5
  • 30
  • 56
  • 1
    Should be `Select` instead of `SelectMany`, otherwise, this should work. Also you could use `First` instead of `FirstOrDefault`, since each group will have at least one element, so using the `...OrDefault` variant is pointless. Since the elements of the collections won't match using the `Default`-comparer, `Union` is equivalent to `Concat` here, probably a (very little bit) slower. – sloth May 08 '13 at 10:03
  • Yes I just noticed about SelectMany. As for FirstOrDefault, you're perfectly right but it's kind of an habit for me to use it. ;) – Serge May 08 '13 at 10:13
-2

Try using .Distinct(). See the link below for more info:

LINQ: Distinct values

Community
  • 1
  • 1
Paul Coghill
  • 667
  • 6
  • 27