根据键元素的键值对列表的交叉数

本文关键字:列表 键值对 键元 元素 | 更新日期: 2023-09-27 18:31:24

我有很多类型的列表:

public List<KeyValuePair<KeyValuePair<string, string>, 
                  List<KeyValuePair<string, string>>>> rawComparisonObject;

我想根据构造列表的键值对的"键"来获取这些列表的交集

我试过了:
List2 = list1.Intersect(list2).Intersect(list3)......等,但如您所见,它与所有键值对变量相交,而不是我想要的那个。

我也试过键值对键上的交叉列表?

采用以下形式:

    public List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> getCommon(List<ResourceInformation> input)
    {
        List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> rawComparisonObject =
            new List<List<KeyValuePair<KeyValuePair<string,string>,List<KeyValuePair<string,string>>>>>();
        foreach (ResourceInformation item in input)
        {
            rawComparisonObject.Add(item.rawComparisonObject);                
        }
        foreach (List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>> item in rawComparisonObject)
        {
        }
        List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> common =
            new List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>>();
        for (int i = 0; i < (rawComparisonObject.Count-1); i++)
        {
            var keysFromB = new HashSet<KeyValuePair<string, string>>(rawComparisonObject[i].Select(x => x.Key));
            var result = rawComparisonObject[i+1].Where(x => keysFromB.Remove(x.Key));
            common.Add(result.ToList());
        }
        return common;
    }

它返回了非常错误的值,有吗有什么简单的方法可以做到这一点吗?


我在链接数据工作中使用此数据结构,通过比较对象来获取公共对象

例如:蝙蝠侠大战盗梦空间

应返回:

类型 : 电影 |电影

主演: 克里斯蒂安·贝尔 |莱昂纳多·迪卡普里奥

当然,所有内容都用它的 URI 链接突出显示,这就是为什么我需要 keyValuePair 一个用于 URI,另一个用于标签......

我尽力解释这种复杂的数据结构。 希望足够清楚

根据键元素的键值对列表的交叉数

据我了解您编写的代码,这是我(修订后的)翻译:

public List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> getCommon(List<ResourceInformation> input)
{
    var rawComparisonObject = 
        input.Select(item => item.rawComparisonObject).ToList();
    var common = rawComparisonObject.Zip(
        rawComparisonObject.Skip(1), 
        (prevItems, nextItems) => 
            (from next in nextItems
            join prev in prevItems on next.Key equals prev.Key
            select next).ToList()).ToList();
    return common;
}

编辑:上面的翻译省略了中间的空 foreach 循环,并使用连接作为过滤器,仅投影通过连接条件的"next"元素。我倾向于加入这种过滤,因为我知道它利用幕后的哈希来有效地执行它所做的匹配。

我以前的版本的问题在于它使用"组连接"变量收集连接结果,这导致了我们不想要的额外枚举。更改后,内部ToList()类似于帖子中提供的原始代码示例中的result变量。外部ToList()是结果的最终common变量(重新)打包。我相信这将提供类似于原始代码的结果;但是,我强烈建议进行测试以验证结果是否符合预期。

恕我直言,正确的做法是重构以简化泛型的使用,直到我们可以更好地推理它们。在一次简短的临时尝试中,我将GetCommon更改为这样的泛型类型(后来将其更改回来):

public List<List<KeyValuePair<T, List<T>>>> GetCommon<T>(/*List<ResourceInformation> input*/)

从那里,我们可以将rawComparisonObject列表提升为方法的参数 - 在此过程中,我们将替换方法的当前参数。使用 var 类型可以让我们避免更改 common 局部变量的类型(只要我们注意输出类型与预期的返回类型匹配,这对原始翻译来说是不好的。

还有更多的设计想法和问题,我在这里可以舒适地检查,所以我将在不尝试这样做的情况下结束。我确实想提出这是一个很好的挑战 - 有时 LINQ 不是正确的选择,但即使它不是正确的选择,方法的改变也可以使其值得尝试。谢谢!

您可以使用

linq 执行此操作,尽管您可能应该更改数据模型以提高效率:

var keys = list1.select( kv => kv.Key).intersection(list2.select(kv => kv.Key)
var result = list1.where( key => keys.contains(key).TolLst()

如果您只想在键上与 KeyValuePair 相交,则应实现一个自定义IEqualityComparer<T>并使用如下所示Intersect()方法:

class KeyValyePairComparer : IEqualityComparer<KeyValuePair<string, string>>
{
    public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y)
    {
        return x.Key == y.Key;
    }
    public int GetHashCode(KeyValuePair<string, string> item)
    {
        return item.Key.GetHashCode();
    }
}

使用上面的实现,您可以获得与查询的交集:

var comparer = new KeyValuePairComparer();
var intersection = list1.Intersect(list2, comparer).Intersect(list3, comparer);