【问题标题】:Select duplicated items with non duplicates in the same collection选择同一集合中不重复的重复项
【发布时间】:2020-03-06 10:15:11
【问题描述】:

(已编辑)

这是我的代码,其中包含我正在使用的集合的示例: 这就是我写myProducts1myProducts1 是嵌套集合时的意思

List<MyProducts> myProducts1= {
new MyProducts{id = 1, Name = "product1", isExcl= true},
new MyProducts{id = 2, Name = "product2", isExcl= false},
new MyProducts{id = 3, Name = "product3", isExcl= true},
new MyProducts{id = 4, Name = "product4", isExcl= false}
}
List<MyProducts> myProducts2= {
new MyProducts{id = 5, Name = "product5", isExcl= true},
new MyProducts{id = 6, Name = "product6", isExcl= false}
}
IEnumerable<SelectedProductRequest> selectedProducts = {
new SelectedProductRequest {id = 1, Name = "product1", Price = 23},
new SelectedProductRequest {id = 1, Name = "product1", Price = 44},
new SelectedProductRequest {id = 2, Name = "product2", Price = 11},
new SelectedProductRequest {id = 6, Name = "product6", Price = 34},
}

List<CategoryProduct> productsWithCategories = {
{CategoryName= "Category1", categoryProduct = myProducts1 },
{CategoryName= "Category2", categoryProduct = myProducts2 }
}

这是我的第一个代码:

IEnumerable<SelectedProductViewModel> products1 = 
.GroupBy(categoryProduct => categoryProduct .CategoryName)
                .Select(categoryProduct => new ProductCategoryViewModel(
                    categoryProduct .Key,
                    categoryProduct 
.Select(product => new SelectedProductViewModel(
                            product.Name,
                            selectedProducts.FirstOrDefault(selectedProduct => selectedProduct.id== product.id)?.Price ?? 0,
                            product.IsExclusive))
                        .OrderByDescending(product => product.id)))

这是我的第二个代码:

IEnumerable<SelectedProductViewModel> products2 = 
.GroupBy(categoryProduct => categoryProduct .CategoryName)
                .Select(categoryProduct => new ProductCategoryViewModel(
                    categoryProduct .Key,
                    categoryProduct
.Join(contractSelectedProducts, product => product.id, selected => selected.id, (product, selected) =>
                            new SelectedProductViewModel(
                            product.Name,
                            selected?.Price ?? 0,
                            product.IsExclusive))

我用这些代码得到的结果:

products1= {"Category1",{
new SelectedProductRequest {id = 1, Name = "product1", Price = 23, IsExclusive = true},
new SelectedProductRequest {id = 2, Name = "product2", Price = 11, IsExclusive = false},
new SelectedProductRequest {id = 3, Name = "product3", Price = 0, IsExclusive = true},
new SelectedProductRequest {id = 4, Name = "product4", Price = 0, IsExclusive = false}
},
"Category2", {new SelectedProductRequest {id = 5, Name = "product5", Price = 0, IsExclusive = true},
new SelectedProductRequest {id = 6, Name = "product6", Price = 34, IsExclusive = false}}

products2= {"Category1",{
new SelectedProductRequest {id = 1, Name = "product1", Price = 23, IsExclusive = true},
new SelectedProductRequest {id = 1, Name = "product1", Price = 44, IsExclusive = true},
new SelectedProductRequest {id = 2, Name = "product2", Price = 11, IsExclusive = false}
}},
"Category2", {new SelectedProductRequest {id = 6, Name = "product6", Price = 34, IsExclusive = false}

但是我想要达到的结果是这样的:

products= {"Category1",{
new SelectedProductRequest {id = 1, Name = "product1", Price = 23, IsExclusive = true},
new SelectedProductRequest {id = 1, Name = "product1", Price = 44, IsExclusive = true},
new SelectedProductRequest {id = 2, Name = "product2", Price = 11, IsExclusive = false},
new SelectedProductRequest {id = 3, Name = "product3", Price = 0, IsExclusive = true},
new SelectedProductRequest {id = 4, Name = "product4", Price = 0, IsExclusive = false}
}},
"Category2",{
{new SelectedProductRequest {id = 5, Name = "product5", Price = 0, IsExclusive = true},
{new SelectedProductRequest {id = 6, Name = "product6", Price = 34, IsExclusive = false}
}

(修改后的代码)

我的问题:如何在不使用products1products2 的情况下实现此结果?或者我怎样才能以更好的方式做到这一点?

【问题讨论】:

  • 嗯,你也可以在这里使用连接
  • 您想合并到两个都是 SelectedProductRequest 的列表。所以你可以这样做: products1.AddRange(products2);您将获得 7 个项目,然后需要删除重复项。
  • 你的代码有什么问题,哪个查询不能正常工作?
  • 我刚刚编辑了我的代码,所以现在我认为它更清晰了

标签: c# linq join


【解决方案1】:

根据评论更新

解决方案一

我将最后一个 Linq 查询更改为:

List<ProductCategory> mergedList = products1
    // concat products2 with products1
    .Concat(products2)
        // group by category name
        .GroupBy(x => x.CategoryName)
            //dictionay(categoryName, list of SelectedProductRequests)
            .ToDictionary(key => key, value => value.SelectMany(x => x.SelectedProductRequests)
                 .GroupBy(x => new { x.id, x.Name, x.Price, x.IsExclusive })
                // take the first in grouped element
                .Select(x => x.First())
                //convert to SelectedProductRequest
                .Select(x => new SelectedProductRequest { id = x.id, Name = x.Name, Price = x.Price, IsExclusive = x.IsExclusive })
                .OrderBy(x => x.id)//order by id
                .ToList())
            .Select(x => new ProductCategory { CategoryName = x.Key.Key, SelectedProductRequests = x.Value })
            .ToList();

解决方案 2

如果我理解您的需求,您需要构建productsWithCategories 以通过一个linq 请求获得预期结果,然后使用GroupJoin 而不是Join 检查以下命题:

IEnumerable<ProductCategoryViewModel> result = productsWithCategories
    .Select(x => new ProductCategoryViewModel
    {
        CategoryName = x.CategoryName,
        SelectedProductViewModels = x.categoryProduct
            .GroupJoin(selectedProducts, prd => prd.id, sel => sel.id,
                (prd, sel) => sel != null && sel.Any() ?
                sel.Select(y =>
                    new SelectedProductViewModel
                    {
                        id = prd.id,
                        isExcl = prd.isExcl,
                        Name = prd.Name,
                        Price = y.Price
                    }).ToList() :
                    new List<SelectedProductViewModel>
                    {
                        new SelectedProductViewModel
                        {
                            id = prd.id,
                            isExcl = prd.isExcl,
                            Name = prd.Name,
                            Price = 0
                        }
                    })
                    .SelectMany(z => z)
                    .ToList()
    });

希望能帮你解决问题

【讨论】:

  • 谢谢,但是请您再看一下这个问题,我进行了编辑,阐明了我希望如何实现结果。感谢您的宝贵时间
  • 现在更复杂了:),我已经更新了我的答案,希望能给你带来预期的结果。
  • 感谢您的回答,是否有可能以更好的方式做到这一点?不必使用products1products2,因为我认为它的代码太多,也许可以一次完成?你怎么看?
  • 不客气,是的,我们可以通过一个linq 请求来做到这一点:你能检查我的第二个解决方案吗,我只使用了productsWithCategoriesselectedProducts 来构建预期的结果
【解决方案2】:

你可以使用Concat方法加入数组:

var selectedProductsMapped = selectedProducts.Select(s => new SelectedProductRequest
{
    id = s.id,
    Name = s.Name,
    Price = s.Price,
    isExclusive = myProducts.Where(p => p.id == s.id).FirstOrDefault().isExclusive
});

var exlcludedProducts = myProducts.Where(p => !selectedProducts.Any(sp => sp.id == p.id))
    .Select(s => new SelectedProductRequest
    {
         id = s.id,
         Name = s.Name,
         Price = 0                
    });

var result = selectedProductsMapped.Concat(exlcludedProducts);

一个例子:

var selectedProducts = new List<SelectedProductRequest> {
     new SelectedProductRequest {id = 1, Name = "product1", Price = 23},
     new SelectedProductRequest {id = 1, Name = "product1", Price = 44},
     new SelectedProductRequest {id = 2, Name = "product2", Price = 11}
};

var myProducts = new List<MyProducts> {
    new MyProducts{id = 1, Name = "product1", isExclusive= true},
    new MyProducts{id = 2, Name = "product2", isExclusive= false},
    new MyProducts{id = 3, Name = "product3", isExclusive= true},
    new MyProducts{id = 4, Name = "product4", isExclusive= false}
};


var selectedProductsMapped = selectedProducts.Select(s => new SelectedProductRequest
{
    id = s.id,
    Name = s.Name,
    Price = s.Price,
    isExclusive = myProducts.Where(p => p.id == s.id).FirstOrDefault().isExclusive
});

var exlcludedProducts = myProducts.Where(p => !selectedProducts.Any(sp => sp.id == p.id))
    .Select(s => new SelectedProductRequest
    {
         id = s.id,
         Name = s.Name,
         Price = 0                
    });

var result = selectedProductsMapped.Concat(exlcludedProducts);

【讨论】:

  • 谢谢,但是请你看一下编辑,困难在于我正在处理嵌套集合,否则我可以使用Concat()Union()来合并两个集合.
【解决方案3】:

您可以使用 Linq 的 Union() 生成 products1 和 products2 的集合。您将需要实现SelectedProductRequestGetHashCode()

products = products1.Union(products2);

Try it Online!

将此添加到SelectedProductRequest

public class SelectedProductRequest : IEquatable<SelectedProductRequest>
{
    public int id {get;set;}
    public string Name {get;set;}
    public int Price {get;set;}
    public bool IsExclusive {get;set;}

    public bool Equals(SelectedProductRequest other) => other is null
        && this.id == other.id
        && this.Name == other.Name
        && this.Price == other.Price
        && this.IsExclusive == other.IsExclusive;

    public override bool Equals(object obj) => Equals(obj as SelectedProductRequest);
    public override int GetHashCode() => (id, Name, Price, IsExclusive).GetHashCode();
}

【讨论】:

  • 谢谢,但我认为当我写下我正在使用嵌套集合时并不清楚,我已经编辑了我的问题,现在我认为很容易知道我想要如何实现结果。
  • @Mana 我通过了。您上次的修改应该是一个新问题。
  • 不,这是同一个问题,只是添加了完整的示例和代码,以便清楚地表明我正在使用嵌套集合。
猜你喜欢
  • 1970-01-01
  • 2023-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多