C# 如何将查找作为两个旧查找的联合?

C# 如何将查找作为两个旧查找的联合?,c#,.net,linq,C#,.net,Linq,如何从两个旧查找的联合中获得查找?似乎a=a.Union(b)对他们不起作用。如果您有原始列表,查找可能会更容易。如果您使用列表的字典s而不是查找,可能会更容易。但是,仍然可以将两个查找对象合并到一个新对象中。基本思想是从查找中检索原始值,然后从两者的连接集创建新的查找 var a = new[] {"apple","aardvark","barn"}; var b = new[] {"baboon", "candy", "cork"}; var al = a.ToLookup (x =>

如何从两个旧查找的联合中获得查找?似乎
a=a.Union(b)
对他们不起作用。

如果您有原始列表,查找可能会更容易。如果您使用
列表的
字典
s而不是查找,可能会更容易。但是,仍然可以将两个查找对象合并到一个新对象中。基本思想是从查找中检索原始值,然后从两者的连接集创建新的查找

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);

对于数组/列表的任何计数,可以考虑更灵活的方式。例如,创建同义词的查找:

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();
    }
}
public ILookup GetSynonyms()
{
var数据=新[]
{
新[]{“您好”、“您好”、“Пццццц”},
新[]{“再见”、“Tchau”、“再见”},
新[]{“你好”,“你好”}
};
返回数据
.SelectMany(words=>words.SelectMany(
关键字=>words.Where(word=>word!=关键字)。选择(word=>newtuple(item1:keyWord,item2:word)))
.Distinct(比较器:新的DelegateComparer(等于:等于,hashCode:v=>v.GetHashCode())
.ToLookup(keySelector:k=>k.Item1,elementSelector:e=>e.Item2);
}
公共密封类委托比较程序:IEqualityComparer
{
私有只读函数_等于;
私有只读Func\u哈希代码;
公共委托比较程序(Func equals,Func hashCode)
{
_相等=相等;
_hashCode=hashCode;
}
公共布尔等于(TX,TY)
{
返回_等于(x,y);
}
公共int GetHashCode(T obj)
{
返回_hashCode!=null?_hashCode(obj):obj.GetHashCode();
}
}

我编写了这个扩展方法,它利用了
ILookup
IEnumerable

我还碰巧需要处理不区分大小写的字符串,所以我有一个重载,它需要一个自定义比较器

        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);
    }

如果我对创建查找时使用的任何集合都没有引用,该怎么办?我正在尝试执行与OP相同的操作,但是上面的代码对我没有帮助-事实上,您正在重复keySelector定义,而不是使用grouping.Key来创建查找。我希望使用每个传入查找的键获得更多的通用代码。
    [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"]));
    }