使用linq比较不同类型的列表

时间:2015-02-19 08:08:58

标签: c# linq

我列出了XML的加载。

XML看起来像这样:

<TablesToSynchronize>
<Table name="dbo.Table1" />
<Table name="dbo.Table2" />
<Table name="dbo.Table3" />
<Table name="dbo.Table4" />
</TablesToSynchronize>

我想将XElement的列表与string列表进行比较,但我无法将其整合在一起。

    private static readonly XDocument TableSettings = XDocument.Load(GetAssemblyDirectory() + @"\Tables.xml");
    private static List<XElement> TablesToSync = new List<XElement>();

    static void Main(string[] args)
    {
        {
            var test = TableSettings.Descendants("Table").Select(x => x.Attribute("name").Value.ToString());

            test = test.Where(args.ToList().Contains).ToList();


            var test2 = (from x in TableSettings.Descendants("Table")
                where x.Attribute("name").Value == "dbo.Table1"
                select x).ToList();

            //TablesToSync = ??
        }
    }

var test2工作正常,但只返回带有“Table1”的XElement。我想循环args并检查是否有任何项目匹配XElement属性("name").Value

我在这里缺少什么?

args包含dbo.Table1,dbo.Table2,dbo.Table3

更新:test2给我一个包含dbo.Table1的XElement列表。 test给了我一个string的空列表。

输出应为List<XElement>

2 个答案:

答案 0 :(得分:1)

有两种方法可以使用Where来实现您想要的效果,使用JOIN

来实现第二种方法

您可以应用联接以获得结果

  var mytest = TableSettings.Descendants("Table").Join(arggs, x => x.Attribute("name").Value, y => y, (x, y) => new { Element = x });

您可以将Where应用为

   TablesToSync = TableSettings.Descendants("Table").Where(x => arggs.Contains(x.Attribute("name").Value)).ToList();

如果您的数据很小,那么它不应该为您决定使用哪一项提供很多性能改进。但是如果你有大量的数据阅读评论和更多的东西,你应该自己决定你想要遵循哪种方法。

答案 1 :(得分:1)

以下内容将返回两个元素:

args = new[] { "dbo.Table1", "dbo.Table3" };
var test = (from elt in TableSettings.Descendants("Table")
            where args.Contains(elt.Attribute("name").Value)
            select elt).ToList();
Debug.Assert(test.Count==2);

args = new[] { "dbo.Table1", "dbo.Table3" };
var test = (from elt in TableSettings.Descendants("Table")
            where args.Contains((string)elt.Attribute("name"))
            select elt).ToList();

或作为方法链的等价物:

var test = TableSettings.Descendants("Table")
                        .Where(elt => args.Contains(elt.Attribute("name").Value))
                        .ToList();

XAttribute可显式转换为基本.NET类型之一,因此您必须使用(string)强制转换。否则,.NET会将XAttribute实例与字符串值进行比较。

如果您有很多参数并且担心Contains很慢,您可以将字符串数组转换为字典:

var argsDict = args.ToDictionary(x => x);
var test = TableSettings.Descendants("Table").                    
                Where(elt => argsDict.ContainsKey(elt.Attribute("name").Value))
                .ToList();

对10000000次迭代的快速测试会返回这些非常有意义的结果:

  • 其中:33466320 ticks
  • 加入:32560386 ticks
  • 字典:22998512 ticks
  • HashSet:25979814 ticks

WhereJoin之间的差异可以忽略不计(~2%),很容易归因于噪音。字典或散列集虽然明显更快(~30%)。

事实上,等效方法之间的差异波动很大,基本上没有意义。

这并不令人惊讶,因为字典/ hashset本质上充当了SQL中的索引。事实上,当连接中的两个表中的一个表(相对)很小时,SQL Server将使用散列连接。

如果您需要从参数中访问多个键,字典可能会执行得更好,因为您可以在单个操作中查找和检索匹配值。这类似于在SQL中使用覆盖索引:

MyOtherClass v=null;
var test = from elt in TableSettings.Descendants("Table")
           let value = elt.Attribute("name").Value
           where argsDict.TryGetValue(value, out v)
           select new {elt, v};

这在C#5中相当丑陋。这是C#6中(现已废弃的)声明表达式有帮助的地方:

var test = from elt in TableSettings.Descendants("Table")
           let value = elt.Attribute("name").Value
           where argsDict.TryGetValue(value, out var v)
           select new {elt, v};