How can I sort dynamic XML using LINQ having following precedences:
Sort by node-name
Sort by node-value
Sort by attribute-name
Sort by attribute-value
Sorting by Node Name:
var doc = XDocument.Parse("<data><carrot /><apple /><orange /></data>");
var sortedByNames = doc.Root.Elements().OrderBy(e => e.Name.ToString());
foreach(var e in sortedByNames)
Console.WriteLine (e.Name);
Sorted by Node Value:
var doc = XDocument.Parse("<data><thing>carrot</thing><thing>apple</thing><thing>orange</thing></data>");
var sortedByValue = doc.Root.Elements().OrderBy(e => e.Value.ToString());
foreach(var e in sortedByValue)
Console.WriteLine (e.Value);
It all follows the same pattern... You sort based on the criteria you define in the selector function passed into the OrderBy method.
var data = from item in xmldoc.Descendants("content")
orderby (string)item.Element("title") // by node value
//orderby item.Attribute("something") // by attribute value
select new
{
Title = (string)item.Element("title"),
};
Related
I am trying to create a tree from a somewhat large list of 13883 objects using Linq to sort the objects into their parent and child groups, each object is associated with a parentId, I can group the objects together using
var sortedList = marketItems.GroupBy(p => p.parentId).Select(grp => grp.ToList()).ToList();
but this only sorts them into groups, I'm not yet fluent with linq and cant figure out how to map the children correctly. the null ParentGroup is the top level of the tree. Anyone with more experience with linq able to offer some ideas on how to group the llist correctly.
public JsonResult GetJsTree3Data()
{
var marketItems = new List<JsTree3Node>();
var itemList = new List<JsTree3Node>();
foreach (var group in GenerateGroups(connString))
{
var node = JsTree3Node.NewNode(group.id_str);
node.text = group.name;
node.state = new State(false, false, false);
node.parentId = group.marketParentGroup;
marketItems.Add(node);
}
foreach (var group in GenerateItems(connString))
{
var node = JsTree3Node.NewNode(group.id_str);
node.text = group.name;
node.state = new State(false, false, false);
node.parentId = group.marketParentGroup;
marketItems.Add(node);
}
// Create our root node and ensure it is opened
var root = new JsTree3Node()
{
id = "0",
text = "Market Items",
state = new State(true, false, false)
};
var sortedList = marketItems.GroupBy(u => u.parentId).Select(grp => grp.ToList()).ToList();
root.children = sortedList;
return Json(root, JsonRequestBehavior.AllowGet);
}
The final result I am trying achive is a tree of items that users can choose from. there is only one level of the tree as the children arent ordered in the sorted list
I see, the parents can contain multiple items: I believe this is what you are looking for:
var sortedList = from p in marketItems
group p by p.ParentGroup into Groups
select Groups;
//to access the items in each group individually
foreach (var grouping in sortedList)
{
foreach (var Item in grouping)
{
Item.Description///you can access the individual items from this layer...
}
}
Your code should do this, but to access the grouping items you need to use a nested foreach loop.
I'm not sure what your end goal is, but I'm not sure if what you're trying to do can be strictly done with a single LINQ pass. If it were possible, though, I imagine that it would be quite convoluted. You can do it in two LINQ queries quite simply, though:
var refDict = marketItems.ToDictionary(k => k.Id, v => v);
var groupedList = marketItems.Select(s =>
new
{
Parent = s.ParentGroup == null ? null : refDict[s.ParentGroup],
Child = s
}).ToList();
Then use it like this:
var parent = groupedList[0].Parent;
var child = groupedList[0].Child;
In all honesty, though, you could just keep yourself to the first line of code then query the dictionary for an object's parent yourself if you ever need it.
In my function, I am updating my string DocumentLangaugeString as shown in the code.
Now, I need to add elements to my int[] DocumentLanguagesIds,
The query expression I can use is:
from mi in ContextMenuItems where mi.IsChecked select mi.Data.Id
My int[] is supposed to have items which are checked (IsChecked = true), how do I maintain this array? The function gets called each time a user clicks on the item.
Here the ContextMenuItems is the class property which has the IDs I need to add in my array.
private void ClickOnLanguageContextMenu(LanguageContextMenuItemViewModel item)
{
item.IsChecked = !item.IsChecked;
DocumentLanguagesString = string.Join(", ", from mi in ContextMenuItems where mi.IsChecked select mi.Data.Description);
DocumentLanguagesIds = /*need a way to add ids over here*/
}
Maybe
DocumentLanguagesIds =
(from mi in ContextMenuItems where mi.IsChecked select mi.Data.Id)
.ToArray();
In order to not repeat the query also for the Id property you can do something like this:
var result = (from mi in ContextMenuItems where mi.IsChecked
select new { mi.Data.Description, mi.Data.Id }).ToList();
DocumentLanguagesString = string.Join(", ", result.Select(x => x.Description));
DocumentLanguagesIds = result.Select(x => x.Id).ToArray();
I want to get the name of the node and its corresponding values in a xml file using linq to xml.
I usually do this line of code to get the value of the node and store it in a list
var qry = from c in XElement.Load(commonpath).Elements("Root") select c;
List<string> result = new List<string>();
foreach (var i in qry)
{
result.Add(Convert.ToString(i));
}
But now I want both node name and value to store it in a dictionary
Dictionary<string, double> amount = new Dictionary<string, double>();
var qry = "";//what query here
foreach(var i in qry)
{
amount.Add("Node Name", "Value");
}
So what is the right query for this situation please help. Thanks
I hope this is what you are looking for:
var doc = XDocument.Parse(#"
<root>
<firstname>Lucas</firstname>
<lastname>Ontivero</lastname>
</root>");
var qry = from element in doc.Element("root").Descendants() select element;
var result = qry.ToDictionary(e => e.Name, e => e.Value);
result.ToList().ForEach(x=> Console.WriteLine("{0}:{1}", x.Key, x.Value ));
It prints:
firstname:Lucas
lastname:Ontivero
Let me know if it is useful.
Good luck!
I'm having problems with a LINQ to SQL query in the following scenario:
I have items that have "Tags" applied via a bridge table.
I'm trying to filter a list of items to a subset that contain all of a specified set of tags and return the filtered list of items as the query result.
Tables Involved:
Item (ItemId, Name, ...other fields)
Tag (TagId, TagName)
Item_Tag(ItemId, TagId)
As an example if I had a list of Items with tags:
Item1 w/ (Tag1, Tag2)
Item2 w/ (Tag1, Tag2)
Item3 w/ (Tag1)
and I wanted to get all items where the item has both Tag1 AND Tag2 where the filter requirement is provided as an int[] of the required tagIds.
Assuming the Item and Tag Id's match the number at the end of the name. The filter for this example would be:
int[] tagFilterConditions = int[2]{1, 2};
var query = from i in itemList
//define filter here
where the result would be:
Item1,Item2 (excludes Item 3 b/c it isn't tagged with Tag1 AND Tag2)
I'm having a tough time figuring out how to combine these tables to apply that filter on the source list, I've tried using a predicate builder and various joins but just can't get the correct results.
Thanks, for any help...
// Query for all the items in the list
int[] itemIds = itemList.Select(item => item.ItemId).AsArray();
var query =
db.Item.Where(item =>
itemIds.Contains(item.ItemId));
// Apply each tag condition
foreach (int tagid in tagFilterConditions)
{
int temp = tagid;
query = query.Where(item =>
db.Item_Tag.Exists(item_tag =>
item_tag.ItemId == item.ItemId && item_tag.TagId == temp)));
}
I think the answer to your question is in .Contains(): http://blog.wekeroad.com/2008/02/27/creating-in-queries-with-linq-to-sql
Here's what I think is the relevant snippet from that site to your question:
int[] productList = new int[] { 1, 2, 3, 4 };
var myProducts = from p in db.Products
where productList.Contains(p.ProductID)
select p;
Hope this helps!
Here is some sql.
and here is the LinqToSql..
Got the following query to work using an anonymous type after defining the proper foreign key relationships the query was adapted from an answer on this question.
//the tagId's that the item in itemList must have
int[] tagFilterConditions = int[2]{1, 2};
var query =
itemList.Select( i=> new { i, itemTags= item.Item_Tags.Select(it=> it.TagId)})
.Where( x=> tagFilterConditions.All( t=> x.itemTags.Contains(t)))
.Select(x=> x.s);
Lets say I have an array like this:
string [] Filelist = ...
I want to create an Linq result where each entry has it's position in the array like this:
var list = from f in Filelist
select new { Index = (something), Filename = f};
Index to be 0 for the 1st item, 1 for the 2nd, etc.
What should I use for the expression Index= ?
Don't use a query expression. Use the overload of Select which passes you an index:
var list = FileList.Select((file, index) => new { Index=index, Filename=file });
string[] values = { "a", "b", "c" };
int i = 0;
var t = (from v in values
select new { Index = i++, Value = v}).ToList();
You cannot get an index using pure LINQ query expressions (those with from.. where.. select.. clauses).
However, this doesn't mean you have to completely give up on this LINQ query style.
You just have to get out of the LINQ query expression and use a .Select(item, index) method overload.
var newestExistingFilesWithIndexes =
(from f in Filelist
// we love LINQ query expressions
where f.Exists
// and we use it anywhere possible
orderby f.LastModified descending
select f)
// but sometimes we have to get out and use LINQ extension methods
.Select((f, index) => new { Index = index, Filename = f.Fullname});
or suppose, you need to filter a list based on item index ...
var newestExistingFilesOnlyEvenIndexes =
// use the Select method overload to get the index
(from f in Filelist.Select((file, index) => new { file, index })
// only take item with an even index
where f.index % 2 == 0
where f.file.Exists
orderby f.file.LastModified descending
select f.file);