根据Key元素相交的keyValuePair列表的数量

时间:2012-04-18 04:47:57

标签: c# .net linq

我有多个类型列表:

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

我想根据构造List的KeyValuePair的“键”得到这些列表的交集

我试过了:
List2 = list1.Intersect(list2).Intersect(list3)......等,但正如你所看到的那样,将所有KeyValuePair变量相互交叉,而不是我想要的变量。

我也试过了 Intersect lists on KeyValuePair key?

以下表格:

    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;

    }

它返回了非常错误的值, 在那儿 有什么简单的方法吗?


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

Ex:Batman vs. Inception

应该返回:

类型:电影|电影

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

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

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

3 个答案:

答案 0 :(得分: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循环,并使用连接作为过滤器,仅投影通过连接条件的“下一个”元素。我倾向于喜欢加入这种过滤,因为我知道它利用散列下的哈希来有效地执行它的匹配。

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

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

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

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

还有更多的设计理念和问题,而不是我在这里可以轻松地检查,所以我将关闭而不试图这样做。我确实想提出这是一个很好的挑战 - 有时LINQ不是正确的选择,但即使它不是正确的选择,改变方法也可以让它值得尝试。谢谢!

答案 1 :(得分:0)

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

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

答案 2 :(得分: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);