Reputation: 5242
I have a lists the loads from an XML.
The XML looks like this:
<TablesToSynchronize>
<Table name="dbo.Table1" />
<Table name="dbo.Table2" />
<Table name="dbo.Table3" />
<Table name="dbo.Table4" />
</TablesToSynchronize>
I want to compare a list of XElement
with a list of string
, but I can't get it together.
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
is working fine, but it returns only the XElement
with "Table1". I want to loop args and check if any item there matches XElement
attribute ("name").Value
.
What am I missing here?
args contains dbo.Table1, dbo.Table2, dbo.Table3
UPDATE: test2 gives me a list of XElement
containing dbo.Table1. test gives me an empty list of string
.
The output should be a List<XElement>
Upvotes: 0
Views: 179
Reputation: 131364
The following will return two elements:
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);
or
args = new[] { "dbo.Table1", "dbo.Table3" };
var test = (from elt in TableSettings.Descendants("Table")
where args.Contains((string)elt.Attribute("name"))
select elt).ToList();
or the equivalent as a method chain:
var test = TableSettings.Descendants("Table")
.Where(elt => args.Contains(elt.Attribute("name").Value))
.ToList();
An XAttribute explicitly convertible to one of the basic .NET types so you have to use the (string)
cast. Otherwise .NET will compare the XAttribute instance against a string value.
If you have a lot of arguments and worry that Contains
is slow, you can convert the string array to a dictionary:
var argsDict = args.ToDictionary(x => x);
var test = TableSettings.Descendants("Table").
Where(elt => argsDict.ContainsKey(elt.Attribute("name").Value))
.ToList();
A quick test of 10000000 iterations returns these not-very-meaningful results:
The difference between Where
and Join
is negligible (~2%) and can easily be attributed to noise. A dictionary or hashset though is significantly faster (~30%).
In fact, the differences between the equivalent methods fluctuate a lot and are essentially meaningless.
This isn't surprising as a dictionary/hashset is essentially acting as an index would act in SQL. In fact, SQL Server will use hash joins when one of the two tables in a join is (relatively) small.
A dictionary may perform better if you need to access more than the key from the arguments, as you can lookup and retrieve the matching value in a single operation. This is similar to using a covering index in 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};
This is rather ugly though in C# 5. This is where the (now scrapped) declaration expressions in C# 6 would have helped:
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};
Upvotes: 1
Reputation: 8892
There are two approaches to achieve what you want one using the Where
and second using the JOIN
You can apply the join to get your result as
var mytest = TableSettings.Descendants("Table").Join(arggs, x => x.Attribute("name").Value, y => y, (x, y) => new { Element = x });
and you can apply the Where
as
TablesToSync = TableSettings.Descendants("Table").Where(x => arggs.Contains(x.Attribute("name").Value)).ToList();
If your data is small then it should not give lot of performance improvements to which one you decide to use. But if you have large data read comments and more stuff about this you should decide for yourself which approach you want to follow.
Upvotes: 1