Reputation: 2261
I have a DataTable that is filled by a Stored Procedure, and from that datatable which contains a collection of Requests(RequestNumber and Tasks(TaskId)
. When I have reach the first Request number with a Task, I add it to my list, then with additional datarows, I check the list to see if they exist(if(dr["RequestNumber"].ToString() != acList[i].RequestNumber)
) if they do, I delete the dataRow, if not I add them to the list.
This works good in sequential order, but if the datarow and list are off by one it allows the row to be added. Is there any other way to accomplish finding if the value exists in the list.
Thanks in advance.
foreach (DataRow dRow in dt.Rows)
{
DataRow dr = dt.NewRow();
dr["Project"] = dRow["Project"];
dr["RequestNumber"] = dRow["RequestNumber"];
dr["RequestId"] = dRow["RequestId"];
dr["TaskType"] = dRow["TaskType"];
dr["TaskId"] = dRow["TaskId"];
dr["TaskStatus"] = dRow["TaskStatus"];
dr["AssignedTo"] = dRow["AssignedTo"];
dr["DateDue"] = dRow["DateDue"];
if (acList.Count == 0)
{
acList.Add(new AssignedClass
{
Project = dr["Project"].ToString(),
RequestNumber = dr["RequestNumber"].ToString(),
RequestId = dr["RequestId"].ToString(),
TaskType = dr["TaskType"].ToString(),
TaskId = dr["TaskId"].ToString(),
TaskStatus = dr["TaskStatus"].ToString(),
AssignedTo = dr["AssignedTo"].ToString(),
DateDue = dr["DateDue"].ToString()
});
}
else
{
for (int i = 0; i < acList.Count; i++)
{
if(dr["RequestNumber"].ToString() != acList[i].RequestNumber)
{
acList.Add(new AssignedClass
{
Project = dr["Project"].ToString(),
RequestNumber = dr["RequestNumber"].ToString(),
RequestId = dr["RequestId"].ToString(),
TaskType = dr["TaskType"].ToString(),
TaskId = dr["TaskId"].ToString(),
TaskStatus = dr["TaskStatus"].ToString(),
AssignedTo = dr["AssignedTo"].ToString(),
DateDue = dr["DateDue"].ToString()
});
}
else
{
dr.Delete();
}
}
}
Upvotes: 4
Views: 14900
Reputation: 25475
With the option of linq and taking into account that the beginning code block and the check for 0 entries seem a bit redundant. I think the process could boil down to
var distinctRows = dt.Rows.GroupBy(x => x["RequestNumber"]).Select(x => x.First());
acList.AddRange(distinctRows.Select(x => x.MapToAssignedClass());
// Added Mapping method for readability
public static AssignedClass MapToAssignedClass(this DataRow dr)
{
return new AssignedClass
{
Project = dr["Project"].ToString(),
RequestNumber = dr["RequestNumber"].ToString(),
RequestId = dr["RequestId"].ToString(),
TaskType = dr["TaskType"].ToString(),
TaskId = dr["TaskId"].ToString(),
TaskStatus = dr["TaskStatus"].ToString(),
AssignedTo = dr["AssignedTo"].ToString(),
DateDue = dr["DateDue"].ToString()
});
}
Upvotes: 0
Reputation: 10957
This would be a great job for LINQ's Union
method, but it requires an IEqualityComparer<AssignedClass>
implementation. Unless you do this often, it's probably not worth coding (even though it's 10-ish lines if done properly). This would help, however:
acList = acList
.Concat(from row in dt.Rows
from ac in acList
where ac.RequestNumber != row["RequestNumber"].ToString()
select AssignedClassFromDataRow(row))
.ToList();
where
private static AssignedClass AssignedClassFromDataRow(DataRow row)
{
// maybe some checks...
return new AssignedClass
{
Project = dRow["Project"].ToString(),
RequestNumber = dRow["RequestNumber"].ToString(),
RequestId = dRow["RequestId"].ToString(),
TaskType = dRow["TaskType"].ToString(),
TaskId = dRow["TaskId"].ToString(),
TaskStatus = dRow["TaskStatus"].ToString(),
AssignedTo = dRow["AssignedTo"].ToString(),
DateDue = dRow["DateDue"].ToString()
}
}
Slightly more time complex than a hash-based solution, but simple enough to implement.
EDIT:
If you actually need the extra performance provided by hashing, you can write the EqualityComparer (but keep in mind these guidelines). Such solution would look like this in the end:
acList = acList
.Union(
dt.Rows.Select(AssignedClassFromDataRow),
new MyAssignedClassRequestNumberComparer())
.ToList();
Upvotes: 2
Reputation: 1137
You can use HashSet<AssignedClass>
, all you need is to create custom IEqualityComarer<AssignedClass>
in which you check RequestNumber
property of passed objects, and pass instance of this comparer in constructor of HashSet
Edit
Here is possible implementation of IEqualityComarer<AssignedClass>
:
public class AssignedClassComparer : IEqualityComparer<AssignedClass>
{
public bool Equals(AssignedClass x, AssignedClass y)
{
return x.RequestNumber == y.RequestNumber;
}
public int GetHashCode(AssignedClass obj)
{
return obj.RequestNumber.GetHashCode();
}
}
EDIT2: Or you can simply use HashSet to store only keys, while enumerating through rows:
var keys = new HashSet<string>();
foreach (DataRow dRow in dt.Rows)
{
if (keys.Add(dRow["RequestNumber"].ToString()))
{
acList.Add(new AssignedClass
{
Project = dRow["Project"].ToString(),
RequestNumber = dRow["RequestNumber"].ToString(),
RequestId = dRow["RequestId"].ToString(),
TaskType = dRow["TaskType"].ToString(),
TaskId = dRow["TaskId"].ToString(),
TaskStatus = dRow["TaskStatus"].ToString(),
AssignedTo = dRow["AssignedTo"].ToString(),
DateDue = dRow["DateDue"].ToString()
});
}
}
Upvotes: 0
Reputation: 56779
Using LINQ, it's as simple as checking if there are any matches:
if ( !acList.Any(a => a.RequestNumber == dr["RequestNumber"].ToString() )
acList.Add( ... );
Also, it seems that the code at the beginning assigning dRow
to dr
has no purpose. Just use dRow
directly throughout the rest of your code. And I don't think you want to treat (acList.Count == 0)
as a special case, because that just causes you to have to duplicate your logic and thus maintain two separate copies of the same code. So if I understood everything correctly, this simplified code should accomplish the same thing:
foreach (DataRow dRow in dt.Rows)
{
if ( !acList.Any(a => a.RequestNumber == dRow["RequestNumber"].ToString() )
{
acList.Add(new AssignedClass
{
Project = dRow["Project"].ToString(),
RequestNumber = dRow["RequestNumber"].ToString(),
RequestId = dRow["RequestId"].ToString(),
TaskType = dRow["TaskType"].ToString(),
TaskId = dRow["TaskId"].ToString(),
TaskStatus = dRow["TaskStatus"].ToString(),
AssignedTo = dRow["AssignedTo"].ToString(),
DateDue = dRow["DateDue"].ToString()
});
}
}
Upvotes: 5