My solution uses LINQ and a custom Comparer instance to compare the Parameters member and makes some assumptions about the items in Parameters. If those assumptions are correct, though, you could make the implementation simpler by using a Param property like the one suggested in Max's answer. Here's the gist of it:
private static List<Object1> MergeLists(List<Object1> list1, List<Object1> list2)
{
var parameterComparer = new ParameterComparer();
var distinctParameters = list1.Select(o => o.Parameters)
.Concat(list2.Select(o => o.Parameters))
.Distinct(parameterComparer);
return (from p in distinctParameters
let o1 = list1.SingleOrDefault(o => parameterComparer.Equals(p, o.Parameters))
let o2 = list2.SingleOrDefault(o => parameterComparer.Equals(p, o.Parameters))
let result = o2 ?? o1
select result).ToList();
}
Here's a fuller test-driven answer. First, the Object1 declaration -- I added a helper constructor to make the declarations more succinct:
public class Object1
{
public TimeSpan? Time { get; set; }
public List<string> Parameters { get; set; }
public Object1(TimeSpan? time, params string[] parameters)
{
Time = time;
Parameters = parameters.ToList();
}
}
Next, the TestMethod. I defined the Object1Comparer to make the implementation of the test simpler -- it isn't needed for the solution.
[TestMethod]
public void MergeListsTest()
{
// Arrange
var list1 = new List<Object1>
{
new Object1(null, "1", "1"),
new Object1(null, "1", "2"),
new Object1(null, "1", "3"),
new Object1(new TimeSpan(0, 0, 30), "2", "5")
};
var list2 = new List<Object1>
{
new Object1(new TimeSpan(0, 1, 20), "1", "1"),
new Object1(new TimeSpan(0, 0, 51), "1", "2"),
};
var expected = new List<Object1>
{
new Object1(new TimeSpan(0, 1, 20), "1", "1"),
new Object1(new TimeSpan(0, 0, 51), "1", "2"),
new Object1(null, "1", "3"),
new Object1(new TimeSpan(0, 0, 30), "2", "5")
};
// Act
List<Object1> actual = MergeLists(list1, list2);
// Assert
// Note: need to order the actual result to use CollectionAssert.AreEqual()
List<Object1> orderedActual = actual.OrderBy(o => string.Join(";", o.Parameters)).ToList();
CollectionAssert.AreEqual(expected, orderedActual, new Object1Comparer());
}
public class Object1Comparer : IComparer, IComparer<Object1>
{
public int Compare(Object1 x, Object1 y)
{
if (x.Time == null && y.Time == null) return 0;
if (x.Time == null || y.Time == null) return -1;
int timeComparison = TimeSpan.Compare(x.Time.Value, y.Time.Value);
if (timeComparison != 0) return timeComparison;
if (x.Parameters == null && y.Parameters == null) return 0;
if (x.Parameters == null || y.Parameters == null) return -1;
if (x.Parameters.SequenceEqual(y.Parameters)) return 0;
return -1;
}
public int Compare(object x, object y)
{
if (x is Object1 && y is Object1)
return Compare(x as Object1, y as Object1);
return -1;
}
}
Finally, here's the implementation of MergeLists:
public class ParameterComparer : IEqualityComparer<List<string>>
{
public bool Equals(List<string> x, List<string> y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
return x.SequenceEqual(y);
}
public int GetHashCode(List<string> obj)
{
if (obj == null) throw new ArgumentNullException("obj");
// Note: this is not a safe way to get a hash code,
// but if you're sure that the members are always ordered
// and will never contain a semi-colon, then it will work.
return string.Join(";", obj).GetHashCode();
}
}
private static List<Object1> MergeLists(List<Object1> list1, List<Object1> list2)
{
var parameterComparer = new ParameterComparer();
var distinctParameters = list1.Select(o => o.Parameters)
.Concat(list2.Select(o => o.Parameters))
.Distinct(parameterComparer);
return (from p in distinctParameters
let o1 = list1.SingleOrDefault(o => parameterComparer.Equals(p, o.Parameters))
let o2 = list2.SingleOrDefault(o => parameterComparer.Equals(p, o.Parameters))
let result = o2 ?? o1
select result).ToList();
}
Parametersexists in both lists? Or if more than one value exists in the same list?from o1 in l1 from o2 in l2 where Object1Equal(o1, o2) select o1.Time == null ? new Object1() {Parameters = o1.Parameters, Time = o2.Time} : o1;