Hello everone
I'm removing rows from a dataset. All rows that I want to delete have in common that the column have the same value, hence the .FirstOrDefault(x => x.stock == key) which is an int by the way.
public bool RemoveStock(string tickerName) {
bool couldBeRemoved = false;
int key = this.getKeyFromtickerName(tickerName);
stockDataSet.ListingRow found =
listingDataTable.FirstOrDefault(x => x.stock == key);
while (found != null) {
listingDataTable.RemoveListingRow(found);
found = listingDataTable.FirstOrDefault(x => x.stock == key);
}
listingTa.Update(listingDataTable);
listingDataTable.AcceptChanges();
return couldBeRemoved;
}
edit The time is spent in the loop. I assume that the function .FirstOrDefault starts from the beginning of the dataset and I have around 2.5 milion rows, if I remember correctly. end edit
The function works, but painfully slow. It take an order of 10 - 15 minutes to remove 7000 rows. It has to be a better way but how?
Best regards
Gorgen
You are iterating all the records from the start with your while loop. You could just iterate it once to find the records that need to be removed and then you can remove them in a loop like so:
var itemsToBeRemoved = listingDataTable.Where(x=>x.stock == key).ToList();
foreach (var item in itemsToBeRemoved)
listingDataTable.RemoveListingRow(item);
Related
I have two DataTables: allRows and rowsToDelete. I want to delete rows from allRows that rowsToDelete contains. Both tables have the same structure (same columns and their datatypes), but I can't know exact column names and even their quantity.
object.Equals() method recognizes rows from different tables as not equal so I can't use this approach.
From googling and reading StackOverflow I got an idea that probably it can be even done in one line, but I don't know how to build condition for this case:
allRows = allRows.AsEnumerable().Where(???).CopyToDataTable();
I don't know the structure of your data but generally speaking you can do
var cleanedUp = allRows.Where(row => !rowsToDelete.Any(row2 => row2.Id == row.Id ));
If you don not have any primary key then check multiple columns that combinations(composite key) provide you uniqueness on the behalf of which you can easily delete rows from all rows having similar data exist in rowsTodelete table.
OR
First implement inner join among two tables on similar column for retrieving data that you want to delete and insert that into any temp table and delete this data from allrows table.
Hope that will help you.
Your task has no solution, and you change the conditions,
first you write:
Both tables have the same structure (same columns and their datatypes)
then you write:
That's the problem - structure can be different and there can be no "Id" column
If you can even change the data, you can subtract both tables and investigate their structure, columns, etc. But you insist that you do not know them.
When you find out the structure, the task becomes elementary, smth like this(i use my structure from my own project):
var foo = DbContext
.Set<Task>()
.Select(x => new{x.Assignee, x.Availability})
.ToList();
var foo2 = DbContext
.Set<Task2>()
.Select(x => x)
.ToList();
var bar = foo2.Where(x => foo.Select(y => y.Assignee).Contains(x.Assignee)
&& foo.Select(y => y.Availability).Contains(x.Availability));
DbContext.RemoveRange(bar);
DbContext.SaveChanges();
you can write more elegantly, but it's so obvious
This solution works for any data structure, any columns' number and types.
We present DataRows as arrays and compare each cell.
public static void DeleteCopies(DataTable allRows, DataTable rowsToDelete)
{
foreach (DataRow rowToDelete in rowsToDelete.Rows)
{
foreach (DataRow row in allRows.Rows)
{
var rowToDeleteArray = rowToDelete.ItemArray;
var rowArray = row.ItemArray;
bool equalRows = true;
for (int i = 0; i < rowArray.Length; i++)
{
if (!rowArray[i].Equals(rowToDeleteArray[i]))
{
equalRows = false;
}
}
if (equalRows)
{
allRows.Rows.Remove(row);
break;
}
}
}
}
I am new to C# LINQ Queries.
I wish to access the last record in a table and retrieve the values of 2 columns from it.
Accessing the last row is not proving difficult as I can sort with descending order on a unique integer key where the greater value represents a later addition, but I am not sure how I can return 2 different values(integer and string) using a single query.
Would I have to perform 2 different queries, each querying for one item and return that, or would it be more efficient to have the whole lot in a string, and parse the string elsewhere?
This is what I have so far. I am not certain which way would be better.
public IEnumerable GetDeployHistoryTableDate(int nodeId)
{
if (nodeId == 0)
{
return new List<object>();
}
using (var session = sessionFactoryProject.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var items = session.Query<DeployHistory>()
.Where(i => i.NodeId == nodeId)
.OrderByDescending(i => i.Id)
.Select(i => new
{
i.EndTime,
i.Result
})
.First().ToString();
transaction.Commit();
return items;
}
}
}
lstStudents.First(m => m.Passed == "").PassoutYear= CurrentYear;
is there any other way to update records in bulk like the above statement which updates on the first record in list.
foreach (var student in lstStudents.Where(m => m.Passed == ""))
{
student.PassoutYear = CurrentYear;
}
I have a datatable loaded up with some records and I am then pulling a query from another file and want to check if the ID that I pull in this query exists in my datatable.
foreach (var item in records)
{
bool hasit = dt.AsEnumerable().Any(p => p.Field<string>(0) == item.ID);
if (!hasit)
{
//Logic
}
}
I'm using that .Any() function and expecting it to return true if there is an ID in the first field of the datatable that matches the id in the records collection. It continually returns false though, am I missing something? Is there a better way to do this?
I'm using that .Any() function and expecting it to return true if there is an ID in the first field of the datatable that matches the id in the records collection. It continually returns false
When one uses == it compares object references. I recommend you instead use Equals which will just compare the values. Hence change your statement to
dt.AsEnumerable().Any(p => p.Field<string>(0).Equals(item.ID))
Which will achieve what you are expecting.
The method
.Any(p => p.Field(0) == item.ID)
will return true IF ANY element is found. Your posted code specifies that the next thing you do is ask
if (!hasit)
{
//Logic
}
which means if(NOT any has it)... which is producing the incorrect behavior. Change it to:
if (hasit)
{
//Logic
}
and you'll get the desired results.
Edit: kudos to Cuong Le for the observation.
I would try breaking it up to see if I could find the error:
foreach (var item in records)
{
var enumer = dt.AsEnumerable(); // <-- Check this to make sure it has elements
var filtered = enumer.Any(p => p.Field<string>(0) == item.ID); // <- Check to make sure it has elements
}
I'm having trouble here. I have an observable collection, and I want to delete some of the stuff in it if it meets a certain criteria.
Here's the code:
foreach (Record record in SwearJarController.Records)
{
if (record.Word == "Hi")
{
SwearJarController.Records.Remove(record);
Datastore.DB.Records.DeleteOnSubmit(record);
}
}
Records is the name of the collections, and record is the class. Apparently, it gets confused at the 'foreach' part.
What should I do?
Thanks!
You cannot modify a collection that you are enumerating. You must do a ToArray() or ToList() on your foreach:
foreach (Record record in SwearJarController.Records.ToArray())
{
if (record.Word == "Hi")
{
SwearJarController.Records.Remove(record);
Datastore.DB.Records.DeleteOnSubmit(record);
}
}
Cleaned up version:
foreach (Record record in SwearJarController.Records
.Where(x => String.Equals(x.Word, "Hi")
.ToArray())
{
SwearJarController.Records.Remove(record);
Datastore.DB.Records.DeleteOnSubmit(record);
}
Note: You should really use String.Equals(...) and use a StringComparison enumeration as well. I'm not sure if your comparison was meant to be case sensitive and/or ordinal/currentculture/invariantculture.
You can't modify the collection while you are working on it. You can run a for loop with the count going from Records.Count down to 0 and remove that way. That should work
Example:
for(int x = SwearJarController.Records.Count - 1 ; x >= 0; x--)
{
Record record = SwearJarController.Records[x];
if(record.Word == "Hi")
{
SwearJarController.Records.Remove(record);
Datastore.DB.Records.DeleteOnSubmit(record);
}
}
As others have already said, you can't modify a collection while you are iterating thru it.
Your best bet for deleting your records cleanly is to do the following:
foreach (var record in SwearJarController.Records
.Where(r => r.Word == "Hi")
.ToArray())
{
SwearJarController.Records.Remove(record);
Datastore.DB.Records.DeleteOnSubmit(record);
}
This filters and snapshots your SwearJarController.Records collection before deleting.
Doing the filter first limits the possibility of a large array being created.