9
\$\begingroup\$

I have a method that exacts data from an XML and returns an IEnumerable<Foo>. I am trying to create a method that will merge the results from 2 different XML's files into a single IEnumerable and remove any duplicate data that may be found

A duplicate in this case is defined as 2 Foo objects that have the same Name property even if the other data is different. If there is a duplicate, I always want to keep the Foo from the first IEnumerable and discard the 2nd.

Am I on the right track with this LINQ query, or is there a better way to accomplish what I am trying to do?

public IEnumerable<Foo> MergeElements(XElement element1, XElement element2)
{
 IEnumerable<Foo> firstFoos = GetXmlData(element1); // get and parse first set
 IEnumerable<Foo> secondFoos = GetXmlData(element2); // get and parse second set
 var result = firstFoos.Concat(secondFoos)
 .GroupBy(foo => foo.Name)
 .Select(grp => grp.First());
 return result;
}

The biggest concern I have with this code is that I am not certain the duplicate filtering rules I want will be guaranteed. I know Concat will just append secondFoos to the end of firstFoos, but when calling GroupBy(), will the resulting IGrouping object always have elements in the same order as the source data?

asked Apr 23, 2012 at 17:15
\$\endgroup\$
2
  • \$\begingroup\$ Can you implement Equals() (and preferably also IEquatable<Foo>) on Foo, to compare by Name? \$\endgroup\$ Commented Apr 23, 2012 at 17:34
  • \$\begingroup\$ @svick Foo already does that through overriding Equals() (although it does not implement IEquatable, but I can add it). I thought of using Distinct(), but I've read it is unordered, so I was concerned my filtering rules would not be guaranteed. \$\endgroup\$ Commented Apr 23, 2012 at 17:40

1 Answer 1

8
\$\begingroup\$

With things like this, it's usually best to look at the documentation.

Is your approach with GroupBy() going to work? Yes:

Elements in a grouping are yielded in the order they appear in source.

Can you use Distinct() to do the same thing more concisely? No (at least you shouldn't depend on it):

The Distinct method returns an unordered sequence that contains no duplicate values.

Is there some other way? Yes, you can use Union():

When the object returned by this method is enumerated, Union enumerates first and second in that order and yields each element that has not already been yielded.

So, I think the best way to do it is:

var result = firstFoos.Union(secondFoos);
answered Apr 23, 2012 at 17:56
\$\endgroup\$
1
  • \$\begingroup\$ Great answer. I was pretty sure Distinct() was not my solution, but somehow missed Union() in the documentation. \$\endgroup\$ Commented Apr 23, 2012 at 18:34

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.