как сделать левое соединение между списком и словарем? - PullRequest
0 голосов
/ 27 февраля 2019

Я пытаюсь пересечь список со словарем, который отлично работает:

    public static IDictionary<string, string> GetValues(IReadOnlyList<string> keys, IHeaderDictionary headers)
    {
        return keys.Intersect(headers.Keys)
            .Select(k => new KeyValuePair<string, string>(k, headers[k]))
            .ToDictionary(p => p.Key, p => p.Value);
    }

Использование вышеописанного метода будет примерно таким:

    [TestMethod]
    public void GetValues_returns_dictionary_of_header_values()
    {
        var headers = new List<string> { { "trackingId" }, { "SourceParty" }, { "DestinationParty" } };
        var trackingIdValue = "thisismytrackingid";
        var sourcePartyValue = "thisismysourceparty";
        var destinationPartyValue = "thisismydestinationparty";
        var requestHeaders = new HeaderDictionary
        {
            {"trackingId", new Microsoft.Extensions.Primitives.StringValues(trackingIdValue) },
            {"SourceParty", new Microsoft.Extensions.Primitives.StringValues(sourcePartyValue) },
            {"DestinationParty", new Microsoft.Extensions.Primitives.StringValues(destinationPartyValue) },
            {"randomHeader", new Microsoft.Extensions.Primitives.StringValues("dontcare") }
        };
        var headerValues = HeaderOperators.GetValues(headers, requestHeaders);
        Assert.IsTrue(headerValues.ContainsKey("trackingId"));
        Assert.IsTrue(headerValues.ContainsKey("SourceParty"));
        Assert.IsTrue(headerValues.ContainsKey("DestinationParty"));
        Assert.IsTrue(headerValues.Count == headers.Count);
    }

enter image description here

Однако вместо intersect я хотел бы сделать left join, где, например, если я ищу в словаре значение, которое не существует, оно все равно будетвернуть этот ключ с некоторым значением по умолчанию value.

Например, если мы введем oneMoreKey:

        var headers = new List<string> { { "trackingId" }, { "SourceParty" }, { "DestinationParty" }, {"oneMoreKey"} };

Тогда я ожидаю, что результат этого будет примерно таким:

        var headerValues = HeaderOperators.GetValues(headers, requestHeaders, "myDefaultValue");

Где headerValues:

 {"trackingId", "thisismytrackingid"}
 {"SourceParty", "thisismysourceparty"}
 {"DestinationParty", "thisismydestinationparty"}
 {"oneMoreKey", "myDefaultValue"}

Как добавить значение по умолчанию для пересечения, если оно не существует?

Ответы [ 3 ]

0 голосов
/ 28 февраля 2019

Попробуйте этот Linq в вашей функции GetValues:

return keys.Intersect(headers.Keys)
    .Select(k => new KeyValuePair<string, string>(k, headers[k]))
    .Union(keys.Where(k => !headers.Keys.Contains(k)).Select(k => new KeyValuePair<string, string>(k, "myDefaultValue")))
    .ToDictionary(p => p.Key, p => p.Value);

Он объединяет любые значения в ключах словаря заголовка, которые невозможно найти в списке ключей, и связывает их со значением по умолчанию.значение.

0 голосов
/ 28 февраля 2019

Основываясь на этом примере: Соединение влево в двух списках и сохранение одного свойства справа с помощью Linq , вы также можете решить его с помощью GroupJoin, например:

public static IDictionary<string, string> GetValues(IReadOnlyList<string> keys, IHeaderDictionary headers, string defaultValue)
{
    return keys.GroupJoin(headers, key => key, header => header.Key, (key, header) => new { key, header })
        .SelectMany(x => x.header.DefaultIfEmpty(), (x, header) => new { x.key, header.Value })
        .Select(x => new KeyValuePair<string, string>(x.key, x.Value))
        .ToDictionary(p => p.Key, p => p.Value ?? defaultValue);
}
0 голосов
/ 28 февраля 2019

Вы можете использовать TryGetValue при создании нового словаря, чтобы заполнить его значениями по умолчанию.

public static IDictionary<string, string> GetValues(IReadOnlyList<string> keys, IHeaderDictionary headers, string defaultValue) 
{
    return keys.ToDictionary(k => k, k => headers.TryGetValue(k, out string val) ? val : defaultValue);
}
...