C# LINQ排序-前三个需要是不同的制造商

C# LINQ排序-前三个需要是不同的制造商,c#,linq,sorting,C#,Linq,Sorting,我的OM有一个“产品”对象。 每个产品都有一个“制造商id”(属性,整数)。 当我有一个要显示的产品列表时,前三个将显示为“特色产品”。 列表已经按照特定的排序顺序排序,将“特色”产品放在列表的第一位 但是,我现在需要确保列表中的特色产品来自不同的制造商。我想调用一个方法来重新排序。试图利用LINQ来查询输入“产品”和“结果” public List<Product> SetFeatures(List<Product> products, int numberOfFeat

我的OM有一个“产品”对象。
每个产品都有一个“制造商id”(属性,整数)。
当我有一个要显示的产品列表时,前三个将显示为“特色产品”。
列表已经按照特定的排序顺序排序,将“特色”产品放在列表的第一位

但是,我现在需要确保列表中的特色产品来自不同的制造商。我想调用一个方法来重新排序。试图利用LINQ来查询输入“产品”和“结果”

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;

}
public List SetFeatures(列出产品、int numberOfFeatures)
{
列出结果;
//确保第二个产品的制造商与第一个不同。。。。
//确保第三个产品的制造商与前两个不同。。。
//…等等…关于numberOfFeatures
返回结果;
}
提前谢谢

澄清:
原始列表按特定顺序排列:“最畅销”,最高排名第一(降序排列)。结果列表应保持此顺序,但调整或移动“向上”项目除外,以便将不同制造商视为前n个功能

如果物品的前n个(numberOfFeatures)都有不同的制造商,则清单根本不需要更改。
e、 g.如果numberOfFeatures=3
产品1-制造商A(第一个功能)
产品2-制造商B(第二个功能)
产品3-制造商C(第三个功能)
产品4-制造商A(…未检查…)
产品5-制造商A(…未检查…)

e、 g.需要调整的案例。。。例如 输入列表
产品1-制造商A
产品2-制造商A
产品3-制造商B
产品4-制造商A
产品5-制造商F
(…我们想要…)
产品1-制造商A(第一个功能)
产品3-制造商B(第二个功能…向上移动)
产品5-制造商F(第三个功能…向上移动)
产品2-制造商A(…向下推列表…)
产品4-制造商A(…按下列表…)

这是通过实施
IComparer
并跟踪遇到的制造商来实现的。如果少于3个,我们会找到一个新的,我们会选择该产品:

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;
        }
    }
}
私有类功能产品比较器:IComparer
{
//OrderBy保留相等元素的顺序
私有常量int_originalOrder=0;
私有常量int_xFirst=-1;
私有常量int _yFirst=1;
私有只读哈希集_manufacturerIds=新哈希集();
私有只读int_numberOfFeatures;
内部特征ProductComparer(int numberOfFeatures)
{
_numberOfFeatures=numberOfFeatures;
}
公共整数比较(产品x、产品y)
{
return\u manufacturerIds.Count==\u numberOfFeatures
?原顺序
:比较器制造商(x,y);
}
私人国际比较制造商(产品x、产品y)
{
如果(!\u manufacturerIds.Contains(x.ManufacturerId))
{
_添加(x.ManufacturerId);
//将现有的特色产品排在新产品之前
返回\u manufacturerIds.Contains(y.ManufacturerId)?\u yFirst:\u xFirst;
}
如果(!\u manufacturerIds.包含(y.ManufacturerId))
{
_添加(y.ManufacturerId);
//将现有的特色产品排在新产品之前
返回\u manufacturerIds.Contains(x.ManufacturerId)?\u xFirst:\u yFirst;
}
其他的
{
返回原订单;
}
}
}

如果我理解正确,我认为这对你有用

您是否在问,使用订购列表“产品”时,具有不同“制造商”的“产品”的第一个“numberOfFeatures”是什么

public List SetFeatures(列出产品、int numberOfFeatures)
{
退货
.GroupBy(p=>p.ManufacturerId)
.Take(numberOfFeatures)
.选择(g=>g.First());
}

编辑结果是不需要
Distinct()
,修改后的代码:

这是你想要的吗

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

请注意,GroupBy将具有正确的排序逻辑,Union将

我认为Bryan将排序逻辑封装得相当好,这不是我想做的事情。我想用一个Foo的例子来展示我对它的看法

        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);
List foos=new List()
{
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 foocomarer()).Take(3.ToList();
var theRest=foos.Except(查询);
query.AddRange(列表);
食物比较器

    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();
    }
}
公共类FooComparer:IEqualityComparer
{
公共布尔等于(Foo x,Foo y)
{
返回x.Blah==y.Blah;
}
公共int GetHashCode(Foo obj)
{
返回obj.Blah.GetHashCode();
}
}

您将(Baz)1、3和6移到顶部,之后剩余的按原始顺序排列。

我不认为这能保证其余记录保持相同的顺序,它只是从每个制造商那里获取第一个产品。这种解决方案比简单地通过产品循环并将其分为两个桶(然后重新连接)要好,或者你只是想看看是否有办法让Linq屈从于你的出价?虽然我理解你的暗示,这是Linq为了Linq的缘故,这可能为时过早。我们正在解决的问题是定制
var result = 
        products
            .GroupBy(x => x.Id)
            .Take(numberOfFeatures)
            .Select(x => x.First())
            .Union(products);
return result.ToList();
        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);
    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();
    }
}