【问题标题】:how to do a left join between a list and a dictionary?如何在列表和字典之间进行左连接?
【发布时间】:2019-02-27 20:58:32
【问题描述】:

我正在尝试将列表与字典相交,效果很好:

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

但是,我想做一个left join,而不是intersect,例如,如果我在字典中搜索一个不存在的值,它仍然会返回带有一些默认值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"}

如果交集不存在,我如何添加默认值?

【问题讨论】:

  • 如果您想从具有唯一值的多个其他列表创建一个列表,您可以使用Union。您只需要提供一个相等比较器,并弄清楚如果值(对于同一个键)在 2 个源之间不同时该怎么办。

标签: c# .net dictionary functional-programming visual-studio-2017


【解决方案1】:

基于这个例子:Left join on two Lists and maintain one property from the right with 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);
}

【讨论】:

  • 谢谢!有什么方法可以进行这些不区分大小写的比较?我想相交但不关心套管
  • 它已经不区分大小写了,但是如果你想改变它,GroupJoin 有一个 IEqualityComparer 比较器参数,所以你可以这样改变它:keys.GroupJoin(headers, key => key, header => header.Key, (key, header) => new { key, header }, StringComparer.OrdinalIgnoreCase)
【解决方案2】:

您可以在创建新字典时使用 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);
}

【讨论】:

    【解决方案3】:

    在你的 GetValues 函数中试试这个 Linq:

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

    它正在与在键列表中找不到的标题字典键中的任何值进行联合,并将它们与默认值配对。

    【讨论】:

    • 谢谢!有什么方法可以进行这些不区分大小写的比较?我想相交但不关心套管
    • 是的 - 您必须按如下方式定义您的字典:var requestHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase),然后还要执行不区分大小写的相交:keys.Intersect(headers .Keys, StringComparer.OrdinalIgnoreCase)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-17
    相关资源
    最近更新 更多