1

我有许多类型的列表:

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

我想根据构造列表的 KeyValuePair 的“键”来获取这些列表的交集

我试过:
List2 = list1.Intersect(list2).Intersect(list3)......etc ,但你可以看到它与所有 KeyValuePair 变量相交,而不是我想要的那个。

我还尝试过 KeyValuePair 键上的相交列表?

采用以下形式:

    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,另一个用于标签....

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

4

3 回答 3

3

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

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 循环,并使用连接作为过滤器,仅投影通过连接条件的“下一个”元素。我倾向于加入这种过滤,因为我知道它在幕后利用散列来有效地执行它所做的匹配。

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

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

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

从那里,我们可以将rawComparisonObject列表提升为方法的参数 - 在此过程中,我们将替换方法的当前参数。使用var类型化允许我们避免更改common局部变量的类型(只要我们小心输出类型与预期的返回类型匹配,这在原始翻译中是我的错误。)

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

于 2012-04-18T06:55:23.490 回答
0

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

var keys = list1.select( kv => kv.Key).intersection(list2.select(kv => kv.Key)
var result = list1.where( key => keys.contains(key).TolLst()
于 2012-04-18T06:45:11.373 回答
0

如果您只想在其键上与 KeyValuePairs 相交,您应该实现一个自定义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);
于 2012-04-18T11:49:10.947 回答