1

リスト/ネストリストの問題から重複アイテムを削除するという古典的な問題があります。ただし、私が従おうとしている特定のルールのため、解決策は単純ではありません。希望どおりに動作するサンプルアプリケーションを作成しました。しかし、それは不格好なようです。私はより優雅で、可能であればより効率的なものを探しています。たぶん、LINQ/拡張メソッドが役立つかもしれません。助言がありますか?


class Program
{
    static void Main(string[] args)
    {
        var sellers = new List<Seller>()
        {
            new Seller()
            {
                Id = 1,
                Products = new List<Product>()
                {
                    new Product() { Sku = "Alpha", Price = 5.0, Shipping = 2.0 },
                    new Product() { Sku = "Beta", Price = 5.0, Shipping = 2.0 }, // more expensive sku within same seller
                    new Product() { Sku = "Beta", Price = 4.0, Shipping = 2.0 },
                    new Product() { Sku = "Gamma", Price = 8.0, Shipping = 2.0 }
                }
            },
            new Seller()
            {
                Id = 2,
                Products = new List<Product>()
                {
                    new Product() { Sku = "Alpha", Price = 5.0, Shipping = 1.0 },
                    new Product() { Sku = "Beta", Price = 5.0, Shipping = 1.0 },
                    new Product() { Sku = "Gamma", Price = 8.0, Shipping = 2.0 }
                }
            }
        };

        // Eliminate duplicate Products amongst all sellers that have matching "Sku".
        // Rules: 
        // Keep the Product with the lowest price. 
        // If price is equal, keep the product with lower shipping.
        // If shipping is also equal, then keep the product with lowest seller Id.
        // If at the end of all comparisons, a seller ends up with no products, then remove that seller.

        // In this example, I expect to have (not necessarily in this order):
        // 1.{Beta, 4.0, 2.0} // Fred.Beta has a lower price than Bob.Beta
        // 1.{Gamma, 8.0, 2.0} // Fred.Gamma is an identical deal to Bob, but Fred is first in the list
        // 2.{Alpha, 5.0, 1.0} // Bob.Alpha has a lower shipping cost than Fred.Alpha

        var newSellers = new List<Seller>();

        foreach (var seller in sellers)
        {
            foreach (var product in seller.Products)
            {
                // TODO: Possible performance improvement? Check for existing seller & product in newSellers before calling any code below.
                var bestSeller = seller;
                var bestProduct = product;
                FindBestSellerAndProduct(sellers, ref bestSeller, ref bestProduct);
                AddIfNotExists(newSellers, bestSeller, bestProduct);
            }
        }

        newSellers.Sort((x, y) => x.Id.CompareTo(y.Id)); // Ensures the list is sorted by seller id... do I really care?
    }

    private static void FindBestSellerAndProduct(IList<Seller> sellers, ref Seller seller, ref Product product)
    {
        string sku = product.Sku;

        foreach (var s in sellers)
        {
            foreach (var p in s.Products.Where(x => x.Sku == sku))
            {
                if ((product.Price > p.Price) ||
                    (product.Price == p.Price && product.Shipping > p.Shipping) ||
                    (product.Price == p.Price && product.Shipping == p.Shipping && seller.Id > s.Id))
                {
                    seller = s;
                    product = p;
                }
            }
        }
    }

    private static void AddIfNotExists(IList<Seller> sellers, Seller seller, Product product)
    {
        var newSeller = sellers.SingleOrDefault(x => x.Id == seller.Id);
        if (newSeller == null)
        {
            // Add input seller and product if seller doesn't already exist in our list.
            newSeller = new Seller() { Id = seller.Id, Products = new List<Product>() };
            newSeller.Products.Add(product);
            sellers.Add(newSeller);
        }
        else
        {
            var newProduct = newSeller.Products.Find(x => x.Sku == product.Sku);
            if (newProduct == null)
            {
                // Add input product if it doesn't already exist in our list
                newSeller.Products.Add(product);
            }
        }
    }

}

// I cannot modify the below classes.
public sealed class Seller
{
    public int Id;
    public List<Product> Products;
}

public sealed class Product
{
    public string Sku;
    public double Price;
    public double Shipping;
}
4

1 に答える 1

3

このクエリは仕事をします

var query = sellers.SelectMany(s => s.Products.Select(p => new { 
                                                   SellerId = s.Id, 
                                                   Product = p })) // 1
                   .OrderBy(x => x.Product.Price) // 2
                   .ThenBy(x => x.Product.Shipping)
                   .ThenBy(x => x.SellerId)
                   .GroupBy(x => x.Product.Sku) // 3
                   .Select(g => g.First()) // 4
                   .GroupBy(x => x.SellerId) // 5
                   .Select(g => new Seller() {  
                        Id = g.Key,
                        Products = g.Select(x => x.Product).ToList() })
                   .ToList();

使い方:

  1. 最初のステップ-匿名タイプのリストにシーケンスをフラット化する{ settlerId, product }
  2. 条件による注文順序- price、、shippingsettlerId
  3. 製品ごとの順序付けられたシーケンスのグループ化sku{ settlerId, product }それは、製品が同じskuであるが、異なる売り手に属する可能性があるのグループを生成します。
  4. 各グループから最初のアイテムを選択します。したがって、すべてのグループはあなたの条件によってソートされ、それは私たちに同じで最も売れている製品を与えるでしょうsku
  5. 次に、階層を再度作成する必要があります。でグループ化してsellerId、最も売れているすべての製品を含むオブジェクトを作成しSellerます(存在する場合)。一部の販売者がベストセラー商品を持っていない場合、この販売者のグループは存在せず、販売者は結果から削除されます。
于 2012-10-25T23:29:57.957 に答える