【问题标题】:Checking duplication in two lists检查两个列表中的重复项
【发布时间】:2014-02-05 07:50:02
【问题描述】:

我正在尝试使用 C# 中的 LINQ 查询检查两个列表中的重复 ID。代码如下:

List<DistributionStandardPackingUnitItems> itemList = new List<DistributionStandardPackingUnitItems>();
List<DistributionStandardPackingUnitItems> prodVariantDetail = new List<DistributionStandardPackingUnitItems>();
private List<DistributionStandardPackingUnitItems> tempDistSPUI
    {
        get
        {
            if (ViewState["tempDistSPUI"] == null)
            {
                return new List<DistributionStandardPackingUnitItems>();
            }
            else
            {
                return (List<DistributionStandardPackingUnitItems>)ViewState["tempDistSPUI"];
            }
        }
        set
        {
            ViewState["tempDistSPUI"] = value;
        }
    }
itemList = this.tempDistSPUI;
        for (int j = 0; j < itemList.Count; j++)
        {
            if (!prodVariantDetail.Any(i => i.id == itemList[j].id))
            {
                prodVariantDetail.Add(itemList[j]);
            }
        }

但是,prodVariantDetail 列表仍然包含重复的 ID。我想知道是否还有其他 LINQ 查询,例如 Where to fix this?提前致谢。

编辑

 protected void lbnAdd_Click(object sender, EventArgs e)
    {
        List<DistributionStandardPackingUnitItems> prodVariantDetail = new List<DistributionStandardPackingUnitItems>();

        int packagesNeeded = prodPackBLL.getPackagesNeededByDistributionID(distributionID);

        // get the last product variant IDs from ViewState
        prodVariantIDList = this.SelectedVariantDetailIDs;

        foreach (RepeaterItem ri in Repeater1.Items)
        {
            GridView gvProduct = (GridView)ri.FindControl("gvProduct");
            foreach (GridViewRow gr in gvProduct.Rows)
            {
                CheckBox cb = (CheckBox)gr.FindControl("cbCheckRow");
                //Prevent gvFinalised to store duplicate products
                if (cb.Checked && !prodVariantIDList.Any(i => i == gvProduct.DataKeys[gr.RowIndex].Value.ToString()))
                {
                    // add the corresponding DataKey to idList
                    prodVariantIDList.Add(gvProduct.DataKeys[gr.RowIndex].Value.ToString());
                }
            }
        }

        for (int i = 0; i < prodVariantIDList.Count; i++)
        {
            prodVariantDetail.Add(packBLL.getProdVariantDetailByID(prodVariantIDList[i]));
        }

        //Check if itemList and prodVariantDetail list contains any duplicate records
        for (int j = 0; j < tempDistSPUI.Count; j++)
        {
            if (!prodVariantDetail.Any(i => i.id == tempDistSPUI[j].id))
            {
                prodVariantDetail.Add(tempDistSPUI[j]);
            }
        }

        gvFinalised.DataSource = prodVariantDetail;
        gvFinalised.DataBind();

        foreach (GridViewRow gr in gvFinalised.Rows)
        {
            //Get the product packaging quantity by productName
            string name = gr.Cells[1].Text;
            int productQuantity = packBLL.getProductQuantityByName(name, distributionID);
            TextBox tb = (TextBox)gr.Cells[5].FindControl("tbQuantity");

            if (productQuantity == 0)
            {
                tb.Text = productQuantity.ToString();
            }
            else
            {
                tb.Text = (productQuantity / packagesNeeded).ToString();
            }
        }

        // save prodVariantIDList to ViewState
        this.SelectedVariantDetailIDs = prodVariantIDList;
    }

【问题讨论】:

  • 您的代码不清楚,能否请您在tempDistSPUI属性后面更正您的代码?
  • 重复的问题可能和线程并发有关,你的LINQ没问题。
  • for 块内的代码正确地避免了来自itemList 的重复,但尚不清楚prodVariantDetailfor 块之前会发生什么。 prodVariantDetail 可能在 for 块之前已经包含重复项。
  • @ekad prodVariantDetail 正在从 prodIDList 中获取数据,我从另一个 gridview 检查行。你介意帮我看看编辑过的部分吗?
  • 在将 prodIDList 添加到 prodVariantDetail 之前,我对其进行了检查。

标签: c# asp.net list


【解决方案1】:
var toAdd = itemList.Where(i => !prodVariantDetail.Any(p => p.Id == i.Id));
var query = prodVariantDetail.Concat(toAdd);

【讨论】:

  • 所以我只是用这两行替换整个for循环?
  • Linq 很简洁,顺便说一句,循环除了括号外只有三行
【解决方案2】:

您可以使用 GroupJoin 来处理重复的特定 ID

IEnumerable<DistributionStandardPackingUnitItems> toAdd  = (from first in prodVariantDetail
        join second in itemList
        on first.Id equals second.Id
        into matches
        where matches.Any()
        select first).ToList();

或者你可以使用投影

IEnumerable<DistributionStandardPackingUnitItems> toAdd = (from first in prodVariantDetail
            join second in itemList
            on first.Id equals second.Id
            into matches
            where matches.Any()
            select new {Id=first.Id,Name=first.Name}).ToList();

【讨论】:

  • 有没有办法将最终结果存储到 prodVariantDetail 列表中?使用该列表导致我的代码的其他部分
  • 只需更改选择顺序即可。我已经修改过了。
  • 你也可以使用匿名投影
  • 但是如何将 var toAdd 添加回 prodVariantDetail 并将 prodVariantDetail 用于其余代码
【解决方案3】:

你可以试试这个

var Gdupes= itemList.GroupBy(x => new {x.ID}).Where(x => x.Skip(1).Any()).ToList();
List<DistributionStandardPackingUnitItems> dupes = Gdupes.SelectMany(x => x).ToList();
prodVariantDetail= itemList.Except(dupes).ToList();

代码未测试

【讨论】:

  • 所以我只是用这个替换整个for循环?
  • @Gwen 是的,你可以试试,第一行从 List itemList 中选择重复项到 Gdupes grupby。然后我们把它带到List dupes。然后将 itemList 复制到 prodVariantDetail 除了 dupes
  • 它仍然以某种方式包含重复记录。
【解决方案4】:

以下是您的问题的常见解决方案:

targetItems.AddRange(sourceItems.DistictBy(item => item.Id));

在您的情况下,sourceItemsitemListtargetItemsprodVariantDetail

DistictBy 方法有不同的实现方式:

  1. 您可以从 System.Linq 应用Distinct LINQ。

  2. 使用自定义的DistictBy 方法(例如来自MoreLinq)。

你在这行代码中的问题:

for (int i = 0; i < prodVariantIDList.Count; i++)
{
    prodVariantDetail.Add(packBLL.getProdVariantDetailByID(prodVariantIDList[i]));
}

【讨论】:

  • 你介意给我看一些例子吗?因为我仍然对此感到困惑
  • @Gwen 您可以通过我提供的链接找到示例。顺便说一句,我更喜欢DistinctBy 方法。但是在使用它之前,您应该进行代码重构,因为它既不可读也不可理解。尝试将Click方法拆分成短方法,你会发现项目重复的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-12
  • 1970-01-01
  • 2014-11-09
  • 2020-04-05
  • 1970-01-01
  • 2013-04-16
相关资源
最近更新 更多