Ordinal Position of Element in IENumerable Collection (Linq to XMl ) - c#

How do I embed the ordinal number of element as its attribute in this linq query.
var AllSections = from s in xmlDoc.Descendants("section")
select new
{
id = s.Attribute("id").Value,
themeTitle = s.Element("themeTitle").Value,
themeText = s.Element("themeText").Value,
objects = (from a in AllObjects
join b in s.Descendants("object")
on a.Attribute("accessionNumber").Value equals
b.Attribute("accessionNumber").Value
//select a
select new
{
//index = insert ordinal id/index of element
ObjectTitle = a.Element("ObjectTitle").Value,
ObjectText = a.Element("textentry").Value,
}
)
};

You can't easily do it with a query expression - at least not without a horrible side effect. However, you can easily do it with dot notation for either Select or Where. Given that you've got quite a long query expression, it's probably easiest to embed an extra call to where at the start - assuming you do actually want the index of "s" in the original expression:
var AllSections =
from s in xmlDoc.Descendants("section")
select new
{
id = s.Attribute("id").Value,
themeTitle = s.Element("themeTitle").Value,
themeText = s.Element("themeText").Value,
objects = (from a in AllObjects.Select((Item,Index) => new {Item,Index})
join b in s.Item.Descendants("object")
on a.Item.Attribute("accessionNumber").Value equals
b.Attribute("accessionNumber").Value
//select a
select new
{
//index = insert ordinal id/index of element
Index = a.Index,
ObjectTitle = a.Element("ObjectTitle").Value,
ObjectText = a.Element("textentry").Value,
}
)
};
That's assuming you want the index of a within AllObjects.

#Jon Skeet gave you the appropriate overload of Select to use, and here is it in your query:
var AllSections = from s in xmlDoc.Descendants("section")
select new
{
id = s.Attribute("id").Value,
themeTitle = s.Element("themeTitle").Value,
themeText = s.Element("themeText").Value,
objects = (from a in AllObjects
join b in s.Descendants("object")
on a.Attribute("accessionNumber").Value
equals b.Attribute("accessionNumber").Value
select a).Select((a, index) =>
new
{
Index = index,
ObjectTitle = a.Element("ObjectTitle").Value,
ObjectText = a.Element("textentry").Value,
})
};

Related

More efficient Linq expression

I have this Linq Join
var NewQuote = (from qw in Q
join NW in NewNotes on qw.RECID equals NW.RECID into temp
from j in temp
select new Quotes
{
QuoteNumber = qw.QuoteNumber,
CustPartNumber = qw.CustPartNumber,
ITEMGROUPID = qw.ITEMGROUPID,
LotSize = qw.LotSize,
EAU = qw.EAU,
CONTACTPERSONID = qw.CONTACTPERSONID,
QUOTATIONSTATUS = qw.QUOTATIONSTATUS,
QUOTESENTDATE = qw.QUOTESENTDATE,
PricePerPiece = qw.PricePerPiece,
QuoteValue = qw.QuoteValue,
Email = qw.Email,
RECID = qw.RECID,
Notes = j == null ? "" : j.NOTES
}).ToList();
Q is of the Quote class but I need to add the data to the Notes field from NewNotes. Is there a better way to do this than listing every field from the Quote class? If I have to add fields to Quote then I have to document to come to this section of code and update as well.
Why you create new instances of Quotes if you just want to update one property?
var query = from qw in Q join NW in NewNotes
on qw.RECID equals NW.RECID into temp
from j in temp
select new { Quote = qw, Notes = j?.Notes ?? "" };
foreach(var x in query)
{
x.Quote.Notes = x.Notes;
}

Comparing two large generic lists

I cannot find a specific example of this, so am posting the question. Any help appreciated.
I have two large generic lists, both with over 300K items.
I am looping through the first list to pull back information and generate a new item for a new list on the fly, but I need to search within the second list and return a value, based on THREE matching criteria, if found to add to the list, however as you can imagine, doing this 300k * 300k times is taking time.
Is there any way I can do this more efficiently?
My code:
var reportList = new List<StocksHeldInCustody>();
foreach (var correctDepotHolding in correctDepotHoldings)
{
var reportLine = new StocksHeldInCustody();
reportLine.ClientNo = correctDepotHolding.ClientNo;
reportLine.Value = correctDepotHolding.ValueOfStock;
reportLine.Depot = correctDepotHolding.Depot;
reportLine.SEDOL = correctDepotHolding.StockCode;
reportLine.Units = correctDepotHolding.QuantityHeld;
reportLine.Custodian = "Unknown";
reportLine.StockName = correctDepotHolding.StockR1.Trim() + " " + correctDepotHolding.StockR2.Trim();
//Get custodian info
foreach (var ccHolding in ccHoldList)
{
if (correctDepotHolding.ClientNo != ccHolding.ClientNo) continue;
if (correctDepotHolding.Depot != ccHolding.Depot) continue;
if (correctDepotHolding.StockCode != ccHolding.StockCode) continue;
if (correctDepotHolding.QuantityHeld != ccHolding.QuantityHeld) continue;
reportLine.Custodian = ccHolding.Custodian;
break;
}
reportList.Add(reportLine);
}
As Pranay says, a join is probably what you want:
var query = from correct in correctDepotHoldings
join ccHolding in ccHoldList
on new { correct.ClientNo, correct.Depot,
correct.StockCode, correct.QuantityHeld }
equals new { ccHolding.ClientNo, ccHolding.Depot,
ccHolding.StockCode, ccHolding.QuantityHeld }
// TODO: Fill in the properties here based on correct and ccHolding
select new StocksHeldInCustody { ... };
var reportList = query.ToList();
You could move the data from the lookup list into a dictionary, with the key being a unique hash of the 3 items you are searching on. Then you will have very quick lookups and save millions of iterations.
Check my full post : Linq Join on Mutiple columns using Anonymous type
Make use of Linq inner join that will do work for you.
var list = ( from x in entity
join y in entity2
on new { x.field1, x.field2 }
equals new { y.field1, y.field2 }
select new entity { fields to select}).ToList();
Join of linq on multiple field
EmployeeDataContext edb= new EmployeeDataContext();
var cust = from c in edb.Customers
join d in edb.Distributors on
new { CityID = c.CityId, StateID = c.StateId, CountryID = c.CountryId,
Id = c.DistributorId }
equals
new { CityID = d.CityId, StateID = d.StateId, CountryID = d.CountryId,
Id = d.DistributorId }
select c;
Use LINQ to join the lists and return it how you like.
eg
var list1 = GetMassiveList();
var list2 = GetMassiveList();
var list3 = from a in list1
join b in list2
on new { a.Prop1, a.Prop2 } equals
new { b.Prop1, b.Prop2 }
select new { a.Prop1, b.Prop2 };
To do your outter join, you can use DefaultIfEmpty()
This example is setting your RIGHT part of the join to a default object (often null) for the cases where a join wasn't made.
eg
from a in list1
join b in list2
on new { a.Prop1, a.Prop2 } equals
new { b.Prop1, b.Prop2 }
into outer
from b in outer.DefaultIfEmpty()
select new
Prop1 = a.Prop1,
Prop2 = b != null ? b.Prop2 : "Value for Prop2 if the b join is null"
}

How can I order the output of my long LINQ query by a double and then a string?

I have the following LINQ query:
summaries = from m in _master
join d in _detail on pk + m.RowKey equals d.PartitionKey into outer
from d in outer.DefaultIfEmpty()
select new
{
Position = m.Position,
Title = m.Title,
Detail = ((d == null) ? 0 : 1),
PartitionKey = m.PartitionKey,
RowKey = m.RowKey,
Modified = m.Modified,
ModifiedBy = m.ModifiedBy
} into split
group split by split.Title into g
select new AdminSummary
{
Position = g.Last().Position,
Title = g.Key,
DetailCount = g.Sum(s => s.Detail),
PartitionKey = g.Last().PartitionKey,
RowKey = g.Last().RowKey,
Modified = g.Last().Modified,
ModifiedBy = g.Last().ModifiedBy
};
The query works well but now I would like to do an order by on Position (double) followed by Title (string).
Can someone advise how I can do this?
Can someone tell me how to do the order by?
It's pretty easy:
summaries = summaries.OrderBy(item =>item.Position).ThenBy(item =>item.Title);
Also you can use OrderByDescending() and ThenByDescending() if you need them in descending order
Do this after your above query.
summaries = from s in summaries
orderby s.Position,s.Title
select s

Linq Merge Queries

I have two queries that I would like to merge. This might be a left outer join, but it seems different.
The first query selects distinct stuff from a table:
var d = from d in db.Data
select (d.ID, d.Label, Value = 0).Distinct;
Lets suppose this returns the following:
{1,"Apple",0}
{2,"Banana",0}
{3,"Cabbage",0}
I then have another query that makes a different selection:
var s = from d in db.Data
where d.Label != "Apple"
select (d.ID, d.Label, d.Value);
This returns:
{2,"Banana",34}
{3,"Cabbage",17}
I then want a third query that joins the d and s together based upon their ID and their Label. I want the result to look like this:
{1,"Apple",0}
{2,"Banana",34}
{3,"Cabbage",17}
I'm basically just updating the numbers in the third query, but I have no idea how I should be doing this. It feels like it should be a simple join, but I just cannot get it to work.
This should work:
var query1 = from d in db.Data
select new { d.ID, d.Label, Value = 0 }.Distinct();
var query2 = from d in db.Data
where d.Label != "Apple"
select new { d.ID, d.Label, d.Value };
var result =
from d1 in query1
join d2 in query2 on new { d1.ID, d1.Label } equals new { d2.ID, d2.Label } into j
from d2 in j.DefaultIfEmpty()
select new
{
d1.ID,
d1.Label,
Value = d2 != null ? d2.Value : d1.Value
};
Note: are you sure you want to join on the ID and the label ? It seems rather strange to me... the label shouldn't be part of the key, so it should always be the same for a given ID
Here is one using method chain, which is my personal favorite.
var one = db.Data.Select(f => new {f.Id, f.Label, Value = 0});
var two = db.Data.Select(f => f).Where(f => f.Label != "Apple");
var three = one.Join(two, c => c.Id, p => p.Id, (c, p) => new {c.Id, c.Label, p.Value});
Could you just do
var s = from d in db.Data
select new
{
Id = d.ID,
Label = d.Label,
Value = (d.Label == "Apple" ? 0 : d.Value)
};

Linq to SQL With Left Outer Join and Group By With Sum - How To

I'm trying to transform the SQL Query below into Linq to SQL
select Categorias.IdCategoria, Categorias.Nome, SUM(lancamentos.valor)
from lancamentos
left outer join Categorias on Lancamentos.IdCategoria = Categorias.IdCategoria
where Month(DataLancamento) = 11
and Credito = 1
and Lancamentos.Ocultar = 0
group by Categorias.IdCategoria, Categorias.Nome
This is what I've done
from lancamento in Lancamentos
where lancamento.Credito == true
&& lancamento.Ocultar == false
&& lancamento.DataLancamento.Month == 10
join categoria in Categorias on lancamento.IdCategoria equals categoria.IdCategoria into temp
from lancamentoJoinCategoria in temp.DefaultIfEmpty()
group lancamentoJoinCategoria by new { lancamentoJoinCategoria.IdCategoria, lancamentoJoinCategoria.Nome } into x
select new {
IdCategoria = (int?)x.Key.IdCategoria
, Nome = x.Key.Nome
}
How do I add the SUM(lancamentos.valor) to the linq to sql above ?
It will be:
(from lancamento in Lancamentos
join categoria in Categorias on lancamento.IdCategoria equals categoria.IdCategoria into temp
from lancamentoJoinCategoria in temp.DefaultIfEmpty()
where lancamento.Credito == true
&& lancamento.Ocultar == false
&& lancamento.DataLancamento.Month == 10
group lancamento by new { lancamentoJoinCategoria.IdCategoria, lancamentoJoinCategoria.Nome } into x
select new
{
IdCategoria = (int?)x.Key.IdCategoria,
Nome = x.Key.Nome,
sumValor = x.Sum(a=>a.valor)
});
You use the .Sum() method.
Eg;
Public Sub LinqToSqlCount03()
Dim q = (From o In db.Orders _
Select o.Freight).Sum()
Console.WriteLine(q)
End Sub
according to MSDN there is no query expression equivalent to the Sum() operation.
I provided a little sample how you could use the Method Syntax of Sum() in a query.
Some query operations, such as Count
or Max, have no equivalent query
expression clause and must therefore
be expressed as a method call. Method
syntax can be combined with query
syntax in various ways. For more
information, see LINQ Query Syntax versus Method Syntax (C#).
var example = new[]
{
new { Count = 1, Name = "a" }, new { Count = 2, Name = "b" },
new { Count = 2, Name = "c" }, new { Count = 2, Name = "c" }
};
var result = from x in example
select new
{
x.Name,
Sum = (from y in example
where y.Count.Equals(2)
&& y.Name==x.Name
select y.Count).Sum()
};
var distinct = result.Distinct().ToList();

Categories

Resources