linq Groupby列表“子列表”

时间:2018-06-16 21:09:22

标签: c# linq

我有一个List<Meb>(一个酒吧嵌套),每个嵌套都有一个详细列表。
所有这些条都是唯一的,因为其中的每个元素都是唯一的ID。

现在我想添加一个复选框,以便对所有内部具有相同详细列表的栏进行分组(内部项目列表相同,除了它们的ID,以及我首先设置为-1的一些参数或“”)。这是我为此做的功能:

private List<Meb> GroupIdenticalMeb(List<Meb> mebInput)
{
    List<Meb> retour = new List<Meb>();
    foreach(Meb mebOri in mebInput)
    {
        Meb meb = new Meb();
        meb.ID = -1;
        meb.Number = mebOri.Number;
        meb.Length = mebOri.Length;
        meb.Quantity=mebOri.Quantity;
        foreach(Repere repOri in mebOri.ListReperes)
        {
            Repere rep = new Repere();
            rep.Name = repOri.Name;
            rep.Quantite = repOri.Quantite;
            rep.ID = -1;
            meb.ListReperes.Add(rep);
        }
        retour.Add(meb);


    }
    retour = retour.GroupBy(l => l.ListReperes)
            .Select(cl => new Meb
            {
                ID=-1,
                Number = cl.First().Number,
                Length = cl.First().Length,
                Quantity=cl.Sum(c => c.Quantity),
                ListReperes = cl.First().ListReperes,
            }).ToList();
    return retour;
}

这个想法是:

第一:我创建了一个新的List<Meb>复制原List<Meb>List<Repere>,我也复制它,但将ID设置为“-1”,作为其他属性它们之间可能有所不同。

第二:我在List<Repere>

上创建了一个小组

但最终没有完成groupby,输出仍然与输入相同。

编辑:

我更好地解释了我的对象的结构,因为它似乎不够清楚:

每个Meb对象代表一个光束,每个光束包含Repere对象(细节),这些细节有很多参数,最重要的是ID,Name,Quantity,具体例子:

                           ID    Name        Quantity

Meb1(Quantity1) contains : 11    Repere1     2
                           20    Repere2     1
                           25    Repere3     1

Meb2(Quantity2) contains : 12    Repere1     2
                           24    Repere2     2
                           28    Repere3     1

Meb3(Quantity3) contains : 31    Repere1     2
                           18    Repere2     1
                           55    Repere3     1

So I import my List<Meb>, and I want to group all my Mebs, comparing their details list.
In that case the result would be :

Meb1(Quantity4) contains : 0    Repere1     2
                           0    Repere2     1
                           0    Repere3     1

Meb2(Quantity2) contains : 0    Repere1     2
                           0    Repere2     2
                           0    Repere3     1

3 个答案:

答案 0 :(得分:2)

我建议您在Meb类中添加某种属性来散列所有ListReperes项目,然后对其进行分组。

您可以查看以下链接:How to generate a unique hash for a collection of objects independent of their order

IE然后你会这样做: retour = retour.GroupBy(l =&gt; l.HashReperes),这将为您提供列表的唯一分组列表。

其中HashReperes是提供Reperes List哈希值的属性。

答案 1 :(得分:2)

使用IEquatable。然后你可以使用标准的linq GroupBy()。见下面的代码

    public class Meb : IEquatable<Meb>, INotifyPropertyChanged
    {
        public int ID { get; set; }
        public int Number { get; set; }
        public int Length { get; set; }
        public int Quantity { get; set;}

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private List<Meb> GroupIdenticalMeb(List<Meb> mebInput)
        {

            return mebInput.GroupBy(x => x).Select(x => new Meb() {
                ID = x.First().ID,
                Number = x.First().Number,
                Length = x.First().Length,
                Quantity = x.Sum(y => y.Quantity)
            }).ToList();

        }

        public bool Equals(Meb other)
        {
            if ((this.Number == other.Number) && (this.Length == other.Length) && (this.Quantity == other.Quantity))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        public override int GetHashCode()
        {
            return ID;
        }
    }

如果您不想使用IEquatable,请使用此

       private List<Meb> GroupIdenticalMeb(List<Meb> mebInput)
        {

            return mebInput.GroupBy(x => new { number = x.Number, len = x.Length }).Select(x => new Meb()
            {
                ID = x.First().ID,
                Number = x.Key.number,
                Length = x.Key.len,
                Quantity = x.Sum(y => y.Quantity)
            }).ToList();

        }

比较List使用类似的东西

    public class MyClassA : IEquatable<List<MyClassB>>
    {
        public List<MyClassB> myClassB { get; set; }

        public bool Equals(List<MyClassB> other)
        {
            if(other == null) return false;
            if (this.myClassB.Count() != other.Count()) return false;

            var groupThis = this.myClassB.OrderBy(x => x.propertyA).ThenBy(x => x.propertyB).GroupBy(x => x).ToList();
            var groupOther = other.OrderBy(x => x.propertyA).ThenBy(x => x.propertyB).GroupBy(x => x).ToList();

            if (groupThis.Count() != groupOther.Count) return false;

            for (int i = 0; i < groupThis.Count(); i++)
            {
                if (groupThis[i].Count() != groupOther[i].Count()) return false;
            }
            return true;
        }
        public override int GetHashCode()
        {
            return 0;
        }
    }
    public class MyClassB : IEquatable<MyClassB>
    {
        public int propertyA { get; set; }
        public string propertyB { get; set; }

        public bool Equals(MyClassB other)
        {
            if (other == null) return false;

            if ((this.propertyA == other.propertyA) && (this.propertyB == other.propertyB))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        public override int GetHashCode()
        {
            return 0;
        }

    }

答案 2 :(得分:0)

最后,我可以通过以下方式解决问题:

private List<Meb> GroupIdenticalMeb(List<Meb> mebInput)
{
    List<Meb> retour = new List<Meb>();
    foreach(Meb mebOri in mebInput)
    {
        Meb meb = new Meb();
        meb.ID = -1;
        meb.Number = mebOri.Number;
        meb.Length = mebOri.Length;
        meb.Quantity=mebOri.Quantity;
        foreach(Repere repOri in mebOri.ListReperes)
        {
            Repere rep = new Repere();
            rep.Name = repOri.Name;
            rep.Quantite = repOri.Quantite;
            rep.ID = -1;
            meb.ListReperes.Add(rep);
        }
        retour.Add(meb);
        // Here I added a string property, in which I concatenate 
        //name and quantity of each Repere in my List<Repere>, 
        //so on the end the "SomeString" parameters will be identical
        //for all Meb that have the same List<Repere> (ignoring the IDs).
        foreach(Meb meb in retour)
        {
            meb.SomeString = "";
            foreach(RepereNest rep in meb.ListReperes)
            {
                meb.SomeString += rep.Name + rep.Quantite;
            }
        }


    }
    retour = retour.GroupBy(l => l.SomeString)
            .Select(cl => new Meb
            {
                ID=-1,
                Number = cl.First().Number,
                SomeString=cl.First().SomeString,
                Length = cl.First().Length,
                Quantity=cl.Sum(c => c.Quantity),
                ListReperes = cl.First().ListReperes,
            }).ToList();
    return retour;
}

现在,这是我能找到的唯一方法,不对我的参数进行分组(对于这个没有问题),而是对我的对象List中的参数。我认为这种方法并不是那么糟糕,因为我在Repere对象中也有列表,所以我将来可以使用相同的提示。最后,我只是不明白为什么不能检查我的对象列表何时等于?