如何从2个旧查找联盟中查找?似乎a = a.Union(b)
对他们不起作用。
答案 0 :(得分:15)
如果您拥有查找来自的原始列表,则可能更容易。如果您使用Dictionary
Lists
代替查找,也可能会更容易。但是,仍然可以将两个查找对象合并为一个新对象。基本思想是从查找中检索原始值,然后从两者的连接集中创建新的查找。
var a = new[] {"apple","aardvark","barn"};
var b = new[] {"baboon", "candy", "cork"};
var al = a.ToLookup (x => x[0]);
var bl = b.ToLookup (x => x[0]);
var cl = al.Concat(bl).SelectMany(x => x).ToLookup(x => x[0]);
如果您还不知道原始键选择器功能,则可以使用此变体。
var cl = al.Concat(bl)
.SelectMany(lookup => lookup.Select(value => new { lookup.Key, value}))
.ToLookup(x => x.Key, x => x.value);
答案 1 :(得分:0)
可以考虑更灵活的方式来计算任何数组/列表。例如,创建同义词的查找:
public ILookup<string, string> GetSynonyms()
{
var data = new[]
{
new[] {"hello", "hi there", "привет"},
new[] {"bye", "Tchau", "Adios"},
new[] {"hello", "hi there"}
};
return data
.SelectMany(words => words.SelectMany(
keyWord => words.Where(word => word != keyWord).Select(word => new Tuple<string, string>(item1: keyWord, item2: word))))
.Distinct(comparer: new DelegateComparer<Tuple<string, string>>(equals: Equals, hashCode: v => v.GetHashCode()))
.ToLookup(keySelector: k => k.Item1, elementSelector: e => e.Item2);
}
public sealed class DelegateComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> _equals;
private readonly Func<T, int> _hashCode;
public DelegateComparer(Func<T, T, bool> equals, Func<T, int> hashCode)
{
_equals = equals;
_hashCode = hashCode;
}
public bool Equals(T x, T y)
{
return _equals(x, y);
}
public int GetHashCode(T obj)
{
return _hashCode != null ? _hashCode(obj) : obj.GetHashCode();
}
}
答案 2 :(得分:0)
我写了这个扩展方法,利用了ILookup<TK,TV>
是IEnumberable<IGrouping<TK,TV>>
public static ILookup<TK, TV> Union<TK, TV>(this ILookup<TK, TV> self, IEnumerable<IGrouping<TK,TV>> moreGroupings)
{
return self.Concat(moreGroupings)
.SelectMany(grouping => grouping.Select(val => new KeyValuePair<TK, TV>(grouping.Key, val)))
.ToLookup(kvp => kvp.Key, kvp => kvp.Value);
}
这里有一些测试证明。这里的查找包含字符串,并以其长度为键。
[TestMethod]
public void EmptyLookups_UnionReturnsEmpty()
{
var a = new string[] { }.ToLookup(x => x.Length, x => x);
var b = new string[] { }.ToLookup(x => x.Length, x => x);
var c = a.Union(b);
Assert.AreEqual(0, c.Count);
c = b.Union(a);
Assert.AreEqual(0, c.Count);
}
[TestMethod]
public void OneEmptyLookup_UnionReturnsContentsOfTheOther()
{
var a = new string[] { }.ToLookup(x => x.Length, x => x);
var b = new string[] { "hello", "world" }.ToLookup(x => x.Length, x => x);
var c = a.Union(b);
Assert.AreEqual(1, c.Count);
Assert.AreEqual("helloworld", string.Join("", c[5].OrderBy(x=>x)));
c = b.Union(a);
Assert.AreEqual(1, c.Count);
Assert.AreEqual("helloworld", string.Join("", c[5].OrderBy(x=>x)));
}
[TestMethod]
public void UniqueKeys_UnionAdds()
{
var a = new string[] { "cat", "frog", "elephant"}.ToLookup(x => x.Length, x => x);
var b = new string[] { "hello", "world" }.ToLookup(x => x.Length, x => x);
var c = a.Union(b);
Assert.AreEqual(4, c.Count);
Assert.AreEqual("cat", string.Join("", c[3]));
Assert.AreEqual("frog", string.Join("", c[4]));
Assert.AreEqual("elephant", string.Join("", c[8]));
Assert.AreEqual("helloworld", string.Join("", c[5].OrderBy(x=>x)));
}
[TestMethod]
public void OverlappingKeys_UnionMerges()
{
var a = new string[] { "cat", "frog", "horse", "elephant"}.ToLookup(x => x.Length, x => x);
var b = new string[] { "hello", "world" }.ToLookup(x => x.Length, x => x);
var c = a.Union(b);
Assert.AreEqual(4, c.Count);
Assert.AreEqual("cat", string.Join("", c[3]));
Assert.AreEqual("frog", string.Join("", c[4]));
Assert.AreEqual("elephant", string.Join("", c[8]));
Assert.AreEqual("hellohorseworld", string.Join("", c[5].OrderBy(x=>x)));
}
我也碰巧需要处理不区分大小写的字符串,所以我有一个需要自定义比较器的重载。
public static ILookup<TK, TV> Union<TK, TV>(this ILookup<TK, TV> self, IEnumerable<IGrouping<TK,TV>> moreGroupings, IEqualityComparer<TK> comparer)
{
return self.Concat(moreGroupings)
.SelectMany(grouping => grouping.Select(val => new KeyValuePair<TK, TV>(grouping.Key, val)))
.ToLookup(kvp => kvp.Key, kvp => kvp.Value, comparer);
}
这些示例中的查找使用第一个字母作为键:
[TestMethod]
public void OverlappingKeys_CaseInsensitiveUnionAdds()
{
var a = new string[] { "cat", "frog", "HORSE", "elephant"}.ToLookup(x => x.Substring(0,1), x => x);
var b = new string[] { "hello", "world" }.ToLookup(x => x.Substring(0,1), x => x);
var c = a.Union(b, StringComparer.InvariantCulture);
Assert.AreEqual(6, c.Count);
Assert.AreEqual("cat", string.Join("", c["c"]));
Assert.AreEqual("frog", string.Join("", c["f"]));
Assert.AreEqual("elephant", string.Join("", c["e"]));
Assert.AreEqual("hello", string.Join("", c["h"].OrderBy(x=>x)));
Assert.AreEqual("HORSE", string.Join("", c["H"].OrderBy(x=>x)));
Assert.AreEqual("world", string.Join("", c["w"]));
}
[TestMethod]
public void OverlappingKeys_CaseSensitiveUnionMerges()
{
var a = new string[] { "cat", "frog", "HORSE", "elephant"}.ToLookup(x => x.Substring(0,1), x => x);
var b = new string[] { "hello", "world" }.ToLookup(x => x.Substring(0,1), x => x);
var c = a.Union(b, StringComparer.InvariantCultureIgnoreCase);
Assert.AreEqual(5, c.Count);
Assert.AreEqual("cat", string.Join("", c["c"]));
Assert.AreEqual("frog", string.Join("", c["f"]));
Assert.AreEqual("elephant", string.Join("", c["e"]));
Assert.AreEqual("helloHORSE", string.Join("", c["h"].OrderBy(x=>x)));
Assert.AreEqual("helloHORSE", string.Join("", c["H"].OrderBy(x=>x)));
Assert.AreEqual("world", string.Join("", c["w"]));
}