我查看过本网站上的问题,但没有找到符合我特定问题的内容。
假设我有以下内容:
Product[] store1 = { new Product { Name = "apple", Code = 9, Code1="1" },
new Product { Name = "orange", Code = 4 } };
Product[] store2 = { new Product { Name = "apple", Code = 9, Code2="2" },
new Product { Name = "lemon", Code = 12 } };
使用:
public class Product : IEquatable<Product>
{
public string Name { get; set; }
public int Code { get; set; }
public string Code1 { get; set; }
public string Code2 { get; set; }
public bool Equals(Product other)
{
//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null)) return false;
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, other)) return true;
//Check whether the products' properties are equal.
return Code.Equals(other.Code) && Name.Equals(other.Name);
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public override int GetHashCode()
{
//Get hash code for the Name field if it is not null.
int hashProductName = Name == null ? 0 : Name.GetHashCode();
//Get hash code for the Code field.
int hashProductCode = Code.GetHashCode();
//Calculate the hash code for the product.
return hashProductName ^ hashProductCode;
}
}
如何返回单个Enumerable,其中来自store1的数据被匹配的store2中的数据覆盖,并且在非匹配时从store2插入到store1中。基本上我正在寻找TSQL Merge语句的C#等价物。
运行时的结束时:
foreach (var product in union)
Console.WriteLine(product.Name + " " + product.Code + " " + product.Code1 + " " + product.Code2);
我想回来:
apple 9 1 2
橙色4
lemon 12
然而,当我运行时:
IEnumerable<Product> union = store1.Union(store2);
我明白了:
Apple 9 1
橙色4
lemon 12
当我运行时:
IEnumerable<Product> union = store1.Concat(store2);
我明白了:
Apple 9 1
橙色4
Apple 9 2
lemon 12
提前感谢您的帮助。
答案 0 :(得分:0)
//
// Summary:
// Produces the set union of two sequences by using the default equality comparer.
//
// Parameters:
// first:
// An System.Collections.Generic.IEnumerable<T> whose distinct elements form
// the first set for the union.
//
// second:
// An System.Collections.Generic.IEnumerable<T> whose distinct elements form
// the second set for the union.
//
// Type parameters:
// TSource:
// The type of the elements of the input sequences.
//
// Returns:
// An System.Collections.Generic.IEnumerable<T> that contains the elements from
// both input sequences, excluding duplicates.
//
// Exceptions:
// System.ArgumentNullException:
// first or second is null.
public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second);
因为函数
不包括重复项。
所以你必须为Product []
编写联合函数public static class ProductExtension
{
public static IEnumerable<T> Union<T>(this IEnumerable<T> store1, IEnumerable<T> store2)
{
List<T> List = new List<T>();
foreach (var item in store2)
{
if (store1.Any(n=>n.Equals(item)))
{
var obj = store1.First(n => n.Equals(item));
foreach (System.Reflection.PropertyInfo pi in obj.GetType().GetProperties())
{
object v1 = pi.GetValue(obj, null);
object v2 = pi.GetValue(item, null);
var value = v1;
if (v2 != null && (v1 == null || v1.ToString() == string.Empty) && v1 != v2)
{
value = v2;
}
pi.SetValue(obj, value, null);
}
List.Add(obj);
}
else {
List.Add(item);
}
}
foreach (var item in store1) {
if(!store2.Any(n=>n.Equals(item))){
List.Add(item);
}
}
return List.AsEnumerable();
}
}
答案 1 :(得分:0)
我不会依赖于反射,而是在Product
类中为它编写自己的功能。像AsCombo
或CombineWith
方法:
public IEnumerable<Product> AsCombo(Product p)
{
//if not equal, return both
if (!Equals(p))
{
yield return this;
yield return p;
yield break;
}
//if equal return the one desired by checking all properties
yield return new Product //always better to return new instance for linq queries
{
Name = Name,
Code = Code,
Code1 = Code1 ?? p.Code1, //I give preference to 'this'
Code2 = Code2 ?? p.Code2 //I give preference to 'this'
};
}
现在所有标准的Linq查询都应该有效。
var combo = store1.Concat(store2)
.GroupBy(x => x)
.Where(x => x.Count() == 1)
.Select(x => x.Key) //get non duplicated products
.Concat(store1.Distinct() //concat them with combined form of duplicated products
.Join(store2.Distinct(), x => x, x => x, (x, y) => x.AsCombo(y))
.SelectMany(x => x))
.ToList();
使用下面的查询会更容易,但是那依赖于Union
的实现(假设Union
保留第一个或外部序列的副本并丢弃后续/内部序列的重复项)。不推荐。
var combo = store1.Join(store2, x => x, x => x, (x, y) => x.AsCombo(y))
.SelectMany(x => x)
.Union(store1)
.Union(store2)
.ToList();