开发者

LINQ Sorting - First three need to be different manufacturers

My OM has a 'product' object.

Each product has a 'manufacturer id' (property, integer).

When I have a list of products to display, the first three are displayed as the 'featured products'.

The list is already sorted in a specific sort order, putting the 'featured' products first in the list.

However, I now need to ensure the featured products in the listing are from different Manufacturers. I want to have a method to call to do this re-sorting. Trying to utilize LINQ to to the querying of the input 'products' and the 'results'

public List<Product> SetFeatures(List<Product> products, int numberOfFeatures)
{
    List<Product> result;

    // ensure the 2nd product is different manufacturer than the first ....

    // ensure the 3rd product is a different manufacturer than the first two... 

    // ... etc ... for the numberOfFeatures

    return result;

}

Thanks in advance.

Clarification:

The original list is in a specific order: the 'best selling', highest开发者_高级运维 first (descending order). The resulting list should remain in this order with the exception of adjusting or moving 'up' items so that the differing manufacturers are seen the top n features.

If the first n (numberOfFeatures) of items all have different manufacturers, then the listing does not need to be altered at all.

e.g. If numberOfFeatures = 3

Product 1 - Manufacturer A (1st feature)

Product 2 - Manufacturer B (2nd feature)

Product 3 - Manufacturer C (3rd feature)

Product 4 - Manufacturer A (...not checked...)

Product 5 - Manufacturer A (...not checked...)

e.g. Case to adjust ... for example ... INPUT List

Product 1 - Manufacturer A

Product 2 - Manufacturer A

Product 3 - Manufacturer B

Product 4 - Manufacturer A

Product 5 - Manufacturer F

(... we would want ...)

Product 1 - Manufacturer A (1st feature)

Product 3 - Manufacturer B (2nd feature ... moved up)

Product 5 - Manufacturer F (3rd feature ... moved up)

Product 2 - Manufacturer A (...pushed down the list...)

Product 4 - Manufacturer A (...pushed down the list...)


I think Bryan encapsulated the sorting logic pretty well and it's not something I thought of doing. I'd like to present my take on it anyway using a Foo example.

        List<Foo> foos = new List<Foo>()
    {
        new Foo() { Baz = 1, Blah = "A"},
        new Foo() { Baz = 2, Blah = "A"},
        new Foo() { Baz = 3, Blah = "B"},
        new Foo() { Baz = 4, Blah = "B"},
        new Foo() { Baz = 5, Blah = "B"},
        new Foo() { Baz = 6, Blah = "C"},
        new Foo() { Baz = 7, Blah = "C"},
        new Foo() { Baz = 8, Blah = "D"},
        new Foo() { Baz = 9, Blah = "A"},
        new Foo() { Baz = 10, Blah = "B"},
    };

    var query = foos.Distinct(new FooComparer()).Take(3).ToList();
    var theRest = foos.Except(query);

    query.AddRange(theRest);

FooComparer being

    public class FooComparer : IEqualityComparer<Foo>
{
    public bool Equals(Foo x, Foo y)
    {
        return x.Blah == y.Blah;
    }

    public int GetHashCode(Foo obj)
    {
        return obj.Blah.GetHashCode();
    }
}

You get (Baz) 1, 3, and 6 shifted to top, the remaining in their original order afterwards.


    public List SetFeatures(List products, int numberOfFeatures)
    {
        var manufacturerProducts =
            from product in products
            group product by product.ManufacturerId into productGroup
            select productGroup.First();

        return manufacturerProducts.Take(numberOfFeatures).ToList();
    }

Edit: The question is really about a custom ordering of a list. I chose to describe the comparison itself, and use that to sort:

return products
    .OrderBy(product => product, new FeaturedProductComparer(numberOfFeatures))
    .ToList();

This is done by implementing IComparer<Product> and keeping tracking of the manufacturers that have been encountered. When there are less than 3 and we find a new one, we favor that product:

private class FeaturedProductComparer : IComparer<Product>
{
    // OrderBy preserves the order of equal elements
    private const int _originalOrder = 0;
    private const int _xFirst = -1;
    private const int _yFirst = 1;

    private readonly HashSet<int> _manufacturerIds = new HashSet<int>();
    private readonly int _numberOfFeatures;

    internal FeaturedProductComparer(int numberOfFeatures)
    {
        _numberOfFeatures = numberOfFeatures;
    }

    public int Compare(Product x, Product y)
    {
        return _manufacturerIds.Count == _numberOfFeatures
            ? _originalOrder
            : CompareManufacturer(x, y);
    }

    private int CompareManufacturer(Product x, Product y)
    {
        if(!_manufacturerIds.Contains(x.ManufacturerId))
        {
            _manufacturerIds.Add(x.ManufacturerId);

            // Sort existing featured products ahead of new ones
            return _manufacturerIds.Contains(y.ManufacturerId) ? _yFirst : _xFirst;
        }
        else if(!_manufacturerIds.Contains(y.ManufacturerId))
        {
            _manufacturerIds.Add(y.ManufacturerId);

            // Sort existing featured products ahead of new ones
            return _manufacturerIds.Contains(x.ManufacturerId) ? _xFirst : _yFirst;
        }
        else
        {
            return _originalOrder;
        }
    }
}


Edit turns out Distinct() is not required, the revised code:

Is this what you want?

var result = 
        products
            .GroupBy(x => x.Id)
            .Take(numberOfFeatures)
            .Select(x => x.First())
            .Union(products);
return result.ToList();

Note that GroupBy will have the correct sequence and Union will also


If I understand you correctly I think this will work for you.

Are you asking what are the first "numberOfFeatures" of "Product"s that have different "ManufacturerId"s using the ordered list "products"?

public List<Product> SetFeatures(List<Product> products, int numberOfFeatures)
{
    return products
        .GroupBy(p => p.ManufacturerId)
        .Take(numberOfFeatures)
        .Select(g => g.First());
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜