I am running a process like this:
foreach (var x in App.cardSetWithWordCount.Select((r, i) =>
new { Row = r, Index = i }))
{
// Some code here
}
The code inside this routine takes a long time and what I would like to do is to run this for the first ten rows and then run it again for the remaining rows. Something like this:
// just the first ten rows in App.cardSetWithWordCount
foreach (var x in App.cardSetWithWordCount.Select((r, i) =>
new { Row = r, Index = i }))
{
// Some code here
}
then
// everything else except ten rows in App.cardSetWithWordCount
foreach (var x in App.cardSetWithWordCount.Select((r, i) =>
new { Row = r, Index = i }))
{
// Some code here
}
Is there a way to select just the first ten rows and also a way to skip the first ten that I could apply to the foreach?
You can use
App.cardSetWithWordCount.Take(10)
To get the first 10, and then
App.cardSetWithWordCount.Skip(10)
To skip the first ten
Or I guess you could do it the old fashioned way, iterating over App.cardSetWithWordCount with a for loop.
I have one datatable, say 'dtEmp', with columns [EmployeeID][CompanyID][CompanyName]
and another say 'dtCompany' with columns [CompanyID][CompanyName]
I want to update 'dtEmp' with respective Company names in column [CompanyName]
Plese guide. I tried searching this but I could not find exact words to search :(
How about
for(int i = 0; i < dtCompany.Rows.Count; i++)
{
for(int j = 0 ; j < dtEmp.Rows.Count ; j++)
{
if (Convert.ToString(dtCompany.Rows[i]["CompanyID"]) ==
Convert.ToString(dtEmp.Rows[j]["CompanyID"]))
{
dtEmp.Rows[j]["CompanyName"] =
Convert.ToString(dtCompany.Rows[i]["CompanyName"]);
}
}
}
var result = (from t1 in dtEmp
join t2 in dtCompany on t1.CompanyID equals t2.CompanyID
select new { t1.EmployeeID, t1.CompanyID, t2.CompanyName}).ToList()
I don't know what your long term purpose is for updating the datatable, however using something like this would provide you a list of an anonymous object which would contain the 3 fields that you needed. You could potentially hard cast these to strongly typed Datarows and then create a brand new table (or update your existing one) with each row.
Linq itself cannot do update.
Assuming Typed DataTable, simply:
foreach(var rowEmp in dtEmp)
{
var rowComp = dtCompany
.Where(r => r.CompanyID == rowEmp.CompanyID)
.FirstOrDefault();
if(rowComp == null)
rowEmp.SetCompanyNameNull();
else
rowEmp.CompanyName = rowComp.CompanyName;
}
(Ignoring the case of the content having null or DBNull, do null-check if required please.)
Similar logic is applicable to general DataTable.
How can the query below be modified to include a column for row number (ie: one-based index of results)?
var myResult = from currRow in someTable
where currRow.someCategory == someCategoryValue
orderby currRow.createdDate descending
select currRow;
EDIT1: I'm looking for the results to be {idx, col1, col2...col-n} not {idx, row}.
EDIT2: The row number should correspond to result rows not the table rows.
EDIT3: I DataBind these results to a GridView. My goal was to add a row number column to the GridView. Perhaps a different approach would be better.
Use the method-syntax where Enumerable.Select has an overload with the index:
var myResult = someTable.Select((r, i) => new { Row = r, Index = i })
.Where(x => x.Row.someCategory == someCategoryValue)
.OrderByDescending(x => x.Row.createdDate);
Note that this approach presumes that you want the original index of the row in the table and not in the filtered result since i select the index before i filter with Where.
EDIT: I'm looking for the results to be {idx, col1, col2...col-n} not
{idx, row}. The row number should correspond to result rows not
the table rows.
Then select the anonymous type with all columns you need:
var myResult = someTable.Where(r => r.someCategory == someCategoryValue)
.OrderByDescending(r => r.createdDate)
.Select((r, i) => new { idx = i, col1 = r.col1, col2 = r.col2, ...col-n = r.ColN });
Use this Select method:
Projects each element of a sequence into a new form by incorporating the element's index.
Example:
var myResult = someTable.Where(currRow => currRow.someCategory == someCategoryValue)
.OrderByDescending(currRow => currRow.createdDate)
.Select((currRow, index) => new {Row = currRow, Index = index + 1});
In response to your edit:
If you want a DataTable as result, you can go the non-Linq way by simply using a DataView and add a additional column afterwards.
someTable.DefaultView.RowFilter = String.Format("someCategory = '{0}'", someCategoryValue);
someTable.DefaultView.Sort = "createdDate";
var resultTable = someTable.DefaultView.ToTable();
resultTable.Columns.Add("Number", typeof(int));
int i = 0;
foreach (DataRow row in resultTable.Rows)
row["Number"] = ++i;
what about?
int i;
var myResult = from currRow in someTable
where currRow.someCategory == someCategoryValue
orderby currRow.createdDate descending
select new {Record = i++, currRow};
Just for fun, here's an alternative to Select with two arguments:
var resultsWithIndexes = myResult.Zip(Enumerable.Range(1, int.MaxValue - 1),
(o, i) => new { Index = i, Result = o });
According to you edit 1. NO, YOU CAN'T Linq returns the table as it is. You can build each column, but you lose the power of mapped entities.
This has been asked multiple times before: How do you add an index field to Linq results
There is no straightforward way if want to keep a flat list of columns (i.e. OP's Edit2) and also want a generic solution that works with any IEnumerable without requiring you to list out the set of expected columns.
However, there is a roundabout way to kinda go about it which is to dump the query results into a DataTable using the ToDataTable() method from here and then add a RowNumber column to that table.
var table = query.ToList().ToDataTable();
table.Columns.Add("RowNum", typeof(int));
int i = 0;
foreach (DataRow row in table.Rows)
row["RowNum"] = ++i;
This would likely cause performance issues with large datasets but it's not insanely slow either. On my machine a dataset with ~6500 rows took 33ms to process.
If your original query returned an anonymous type, then that type definition will get lost in the conversion so you'll lose the static typing on the column names of the resulting IEnumerable when you call table.AsEnumerable(). In other words, instead of being able to write something like table.AsEnumerable().First().RowNum you instead have to write table.AsEnumerable().First()["RowNum"]
However, if you don't care about performance and really want your static typing back, then you can use JSON.NET to convert the DataTable to a json string and then back to a list based on the anonymous type from the original query result. This method requires a placeholder RowNum field to be present in the original query results.
var query = (from currRow in someTable
where currRow.someCategory == someCategoryValue
orderby currRow.createdDate descending
select new { currRow.someCategory, currRow.createdDate, RowNum = -1 }).ToList();
var table = query.ToDataTable();
//Placeholder RowNum column has to already exist in query results
//So not adding a new column, but merely populating it
int i = 0;
foreach (DataRow row in table.Rows)
row["RowNum"] = ++i;
string json = JsonConvert.SerializeObject(table);
var staticallyTypedList = JsonConvert.DeserializeAnonymousType(json, query);
Console.WriteLine(staticallyTypedList.First().RowNum);
This added about 120ms to the processing time for my 6500 item dataset.
It's crazy, but it works.
I know I'm late to the party, but I wanted to show what worked for me.
I have a list of objects, and the object has an integer property on it for "row number"... or in this case, "Sequence Number". This is what I did to populate that field:
myListOfObjects = myListOfObjects.Select((o, i) => { o.SequenceNumber = i; return o; }).ToList();
I was surprised to see that this worked.
This one helped me in my case - Excel sheet extraction. anonymous type
var UploadItemList = ItemMaster.Worksheet().AsEnumerable().Select((x, index) => new
{
Code = x["Code"].Value == null ? "" : x["Code"].Value.ToString().Trim(),
Description = x["Description"].Value == null ? "" : x["Description"].Value.ToString().Trim(),
Unit = x["Unit"].Value == null ? "" : x["Unit"].Value.ToString().Trim(),
Quantity = x["Quantity"].Value == null ? "" : x["Quantity"].Value.ToString().Trim(),
Rate = x["Rate"].Value == null ? "" : x["Rate"].Value.ToString().Trim(),
Amount = x["Amount"].Value == null ? "" : x["Amount"].Value.ToString().Trim(),
RowNumber = index+1
}).ToList();
int Lc = 1;
var Lst = LstItemGrid.GroupBy(item => item.CategoryName)
.Select(group => new { CategoryName = group.Key, Items = group.ToList() ,RowIndex= Lc++ })
.ToList();
I have a question about sorting in Datatable. I have a table like below and want to sort it from small to big. The problem is when i have same numbers, i want to have the first as the last and so on...
Table:-----------------------------------After Sorting:
Name Bit Size Name Bit Size (corrected)
A 0 1 A 0 1
C 1 2 C 1 2
B 1 3 B 1 3
D 1 1 D 1 1
Result that i want:
Name Bit Size (corrected)
A 0 1
D 1 1
B 1 3
C 1 2
My Code:
arraySBit.DefaultView.Sort = "Bit";
arraySBit = arraySBit.DefaultView.ToTable();
You can use Linq-To-DataTable:
var tblSorted = table.AsEnumerable()
.OrderBy(r => r.Field<int>("Bit"))
.CopyToDataTable();
Edit: But actually DataView.Sort should also work (tested).
Since you have edited your question. Your requirement seems weired. If the Bit is the same you don't want to order by something but you want to reverse the "order" of the rows of the equal rows (so the Ordinal position in the DataTable).
This does what you want although i'm not sure that it's really what you need:
DataTable tblSorted = table.AsEnumerable()
.Select((Row, Ordinal) => new {Row,Ordinal})
.OrderBy(x => x.Row.Field<int>("Bit"))
.ThenByDescending(x => x.Ordinal)
.Select(x => x.Row)
.CopyToDataTable();
Basically it passes the index of the row in the table via this overload Enumerable.Select into an anonymous type. Then it'll sort by Bit first and the index/ordinal second.
A workaround,
After these lines, you should have result in arrySBit as you want
DataTable arrySBitClone = arrySBit.Copy();
arrySBit.DefaultViewSort.Sort = "Bit";
bool different = false;
for(int i=0; i<arrySBit.Rows.Count; i++)
{
if(arrySBit.Rows[i]["Bit"]!=arrySBitClone.Rows[i]["Bit"])
{
difference = true;
break;
}
}
if(!different)
{
arrySBit = arrySBit.Copy();
}
if i'm getting right your question.
why not use Select?
DataTable dt = arraySBit.Select("", "Bit, Size").CopyToDataTable();
The first parameter of the Select Method is a condition to filter, the second is an Order By, so it should work
I am trying to filter dataset by using linq.It works fine
Problem :
But i try to get column from this it gives me that exception
Enumeration has either not started or has already finished.
here is my code :
foreach (string columnName in SelectedItems)
{
var Rate = (from dr in ds.Tables[0].AsEnumerable()
where dr.Field<double>(columnName) > greater && dr.Field<double>(columnName) < less
select new
{
rate = dr.Field<double>(columnName)
}.rate).ToList();
if (Rate.Count > 50)
{
var avg = Rate.CheckRateValue();
}
i++;
}
i searched on web and find out the problem that dr.Field(columnName) must be use for single time.So how i can get column from linq query after skiping this code from Select new section.
I'm not sure that is your actual problem, but you can try:
var rates = (from dr in ds.Tables[0].AsEnumerable()
let rate = dr.Field<double>(columnName)
where rate > greater && rate < less
select rate).ToList();