4

我有一个由存储过程填充的 DataTable,并且该数据表中包含Requests(RequestNumber and Tasks(TaskId). 当我通过任务达到第一个请求编号时,我将它添加到我的列表中,然后使用其他数据行,我检查列表以查看它们是否存在(if(dr["RequestNumber"].ToString() != acList[i].RequestNumber))如果存在,我删除数据行,如果不我将它们添加到名单。

这按顺序很好,但如果数据行和列表关闭一个,它允许添加行。是否有任何其他方法可以完成查找该值是否存在于列表中。

提前致谢。

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();
        }
      }
    }
4

4 回答 4

5

使用 LINQ,它就像检查是否有任何匹配一样简单:

if ( !acList.Any(a => a.RequestNumber == dr["RequestNumber"].ToString() )
    acList.Add( ... );

此外,似乎一开始分配dRow给的代码dr没有任何目的。只需dRow在其余代码中直接使用即可。而且我认为您不想将(acList.Count == 0)其视为特殊情况,因为这只会导致您必须复制逻辑并因此维护相同代码的两个单独副本。所以如果我理解正确,这个简化的代码应该完成同样的事情:

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()
        });
    }
}
于 2013-03-01T14:55:46.107 回答
2

这对于 LINQ 的Union方法来说将是一项很棒的工作,但它需要一个IEqualityComparer<AssignedClass>实现。除非你经常这样做,否则它可能不值得编码(即使如果做得好它是 10 行左右)。但是,这将有所帮助:

acList = acList
    .Concat(from row in dt.Rows
            from ac in acList
            where ac.RequestNumber != row["RequestNumber"].ToString()
            select AssignedClassFromDataRow(row))
    .ToList();

在哪里

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()
    }
}

比基于散列的解决方案时间复杂一些,但实现起来足够简单。

编辑:

如果您确实需要散列提供的额外性能,您可以编写 EqualityComparer(但请记住这些准则)。这样的解决方案最终看起来像这样:

acList = acList
    .Union(
        dt.Rows.Select(AssignedClassFromDataRow),
        new MyAssignedClassRequestNumberComparer())
    .ToList();
于 2013-03-01T15:06:50.103 回答
0

使用 linq 选项并考虑到开始代码块和检查 0 条目似乎有点多余。我认为这个过程可以归结为

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()
    });
}
于 2013-03-01T15:04:56.427 回答
0

您可以使用HashSet<AssignedClass>,您只需要创建自定义IEqualityComarer<AssignedClass>,在其中检查RequestNumber传递对象的属性,并在构造函数中传递此比较器的实例HashSet

编辑

这是可能的实现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: 或者您可以简单地使用 HashSet 仅存储键,同时通过行枚举:

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()
        });
    }
}
于 2013-03-01T14:51:08.280 回答