14

2つの古いルックアップのユニオンからルックアップを取得するにはどうすればよいですか?a = a.Union(b)彼らにはうまくいかないようです。

4

3 に答える 3

19

ルックアップの元となった元のリストがある場合は、より簡単な場合があります。ルックアップDictionaryの代わりにsを使用した方が簡単な場合もあります。Listsただし、2つのルックアップオブジェクトを新しいオブジェクトにマージすることは引き続き可能です。基本的な考え方は、ルックアップから元の値を取得し、両方の連結セットから新しいルックアップを作成することです。

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);
于 2012-09-18T14:33:46.050 に答える
2

私はこの拡張メソッドを作成しました。これILookup<TK,TV>は、anがIEnumerable<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"]));
    }
于 2020-04-08T04:24:57.607 に答える
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();
    }
}

実行結果

于 2014-12-23T13:55:44.033 に答える