Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 动态列表分组_C#_List_Linq_Grouping - Fatal编程技术网

C# 动态列表分组

C# 动态列表分组,c#,list,linq,grouping,C#,List,Linq,Grouping,我想对包含整数列表的列表进行分组 但是正如您所看到的,groupping是第一个元素,我想按所有元素对它进行分组 例如,如果node.Elements.Count==5预期分组结果应与的相同: var groups = cNodes.GroupBy(node => new { A = node.Elements[0], B = node.Elements[1], C = node.Elements[2], D = node.Elements[3],

我想对包含整数
列表的列表进行分组

但是正如您所看到的,groupping是第一个元素,我想按所有元素对它进行分组

例如,如果
node.Elements.Count==5
预期分组结果应与的相同:

var groups = cNodes.GroupBy(node => new
{
    A = node.Elements[0],
    B = node.Elements[1],
    C = node.Elements[2],
    D = node.Elements[3],
    E = node.Elements[4]
});
我找不到解决办法


谢谢。

您可以使用类似于
节点的功能。使用合适的
IEqualityComparer
获取(5)
,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var cNodes = new List<CNode>
            {
                new CNode{Elements = new List<int>{ 0, 0, 1, 1, 1 } },
                new CNode{Elements = new List<int>{ 0, 0, 0, 1, 1 } },
                new CNode{Elements = new List<int>{ 0, 1, 1, 0 } },
                new CNode{Elements = new List<int>{ 0, 1, 1, 0, 0 } },
                new CNode{Elements = new List<int>{ 0, 0, 0, 0 } },
                new CNode{Elements = new List<int>{ 0, 0, 0, 0 } }
            };

            Console.WriteLine("\tGroup by 2:");
            foreach (var group in cNodes.GroupByElements(2))
                Console.WriteLine($"{string.Join("\n", group)}\n");

            Console.WriteLine("\tGroup by 3:");
            foreach (var group in cNodes.GroupByElements(3))
                Console.WriteLine($"{string.Join("\n", group)}\n");

            Console.WriteLine("\tGroup by all:");
            foreach (var group in cNodes.GroupByElements())
                Console.WriteLine($"{string.Join("\n", group)}\n");
        }
    }

    static class CNodeExtensions
    {
        public static IEnumerable<IGrouping<IEnumerable<int>, CNode>> GroupByElements(this IEnumerable<CNode> nodes) =>
            nodes.GroupByElements(nodes.Min(node => node.Elements.Count));

        public static IEnumerable<IGrouping<IEnumerable<int>, CNode>> GroupByElements(this IEnumerable<CNode> nodes, int count) =>
            nodes.GroupBy(node => node.Elements.Take(count), new SequenceCompare());

        private class SequenceCompare : IEqualityComparer<IEnumerable<int>>
        {
            public bool Equals(IEnumerable<int> x, IEnumerable<int> y) => x.SequenceEqual(y);

            public int GetHashCode(IEnumerable<int> obj)
            {
                unchecked
                {
                    var hash = 17;
                    foreach (var i in obj)
                        hash = hash * 23 + i.GetHashCode();
                    return hash;
                }
            }
        }
    }    

    internal class CNode
    {
        public List<int> Elements;

        public override string ToString() => string.Join(", ", Elements);
    }
}

您可以使用类似于
节点的功能。使用合适的
IEqualityComparer
将(5)
与如下内容结合使用:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var cNodes = new List<CNode>
            {
                new CNode{Elements = new List<int>{ 0, 0, 1, 1, 1 } },
                new CNode{Elements = new List<int>{ 0, 0, 0, 1, 1 } },
                new CNode{Elements = new List<int>{ 0, 1, 1, 0 } },
                new CNode{Elements = new List<int>{ 0, 1, 1, 0, 0 } },
                new CNode{Elements = new List<int>{ 0, 0, 0, 0 } },
                new CNode{Elements = new List<int>{ 0, 0, 0, 0 } }
            };

            Console.WriteLine("\tGroup by 2:");
            foreach (var group in cNodes.GroupByElements(2))
                Console.WriteLine($"{string.Join("\n", group)}\n");

            Console.WriteLine("\tGroup by 3:");
            foreach (var group in cNodes.GroupByElements(3))
                Console.WriteLine($"{string.Join("\n", group)}\n");

            Console.WriteLine("\tGroup by all:");
            foreach (var group in cNodes.GroupByElements())
                Console.WriteLine($"{string.Join("\n", group)}\n");
        }
    }

    static class CNodeExtensions
    {
        public static IEnumerable<IGrouping<IEnumerable<int>, CNode>> GroupByElements(this IEnumerable<CNode> nodes) =>
            nodes.GroupByElements(nodes.Min(node => node.Elements.Count));

        public static IEnumerable<IGrouping<IEnumerable<int>, CNode>> GroupByElements(this IEnumerable<CNode> nodes, int count) =>
            nodes.GroupBy(node => node.Elements.Take(count), new SequenceCompare());

        private class SequenceCompare : IEqualityComparer<IEnumerable<int>>
        {
            public bool Equals(IEnumerable<int> x, IEnumerable<int> y) => x.SequenceEqual(y);

            public int GetHashCode(IEnumerable<int> obj)
            {
                unchecked
                {
                    var hash = 17;
                    foreach (var i in obj)
                        hash = hash * 23 + i.GetHashCode();
                    return hash;
                }
            }
        }
    }    

    internal class CNode
    {
        public List<int> Elements;

        public override string ToString() => string.Join(", ", Elements);
    }
}
你写道:

我想按所有元素对它进行分组

Alex给出的解决方案将只按有限数量的元素分组。你说你想按所有元素对它进行分组,即使你有一个包含100个元素的CNode。此外:如果其中一个CNodes的属性元素等于null,他的解决方案也会崩溃

因此,让我们创建一个满足您需求的解决方案

返回值将是一个组序列,其中每个组都有一个键,这是一个CNODE序列。组中的所有元素都是具有等于键的属性元素的源CNODE

你说的相等是指相等。所以元素[0]==键[0]和元素[1]==键[1]等等

当然,您需要确定元素[0]何时等于键[0]:是否通过引用(相同对象)进行比较?或者,如果两个CNODE具有相同的属性值,它们是否相等?还是要指定一个
IEqualityComparer
,以便在它们具有相同的名称或Id时可以看到它们是相等的

// overload without IEqualityComparer, calls the overload with IEqualityComparer:
IEnumerable<IGrouping<IEnumerable<Cnode>, CNode>> GroupBy(
    this IEnumerable<CNode> cNodes)
{
    return GroupBy(cNodes, null);
}

// overload with IEqualityComparer; use default CNode comparer if paramer equals null
IEnumerable<IGrouping<IEnumerable<Cnode>, CNode>> GroupBy(
    this IEnumerable<CNode> cNodes,
    IEqualityComparer<CNode> cNodeComparer)
{
    // TODO: check cNodes != null
    if (cNodeComparer == null) cNodeComparer = EqualityComparer<CNode>.Default;

    CNodeSequenceComparer nodeSequenceComparer = new CNodeSequenceComparer()
    {
        CNodeComparer = cNodeComparer,
    }
    return sequenceComparer.GroupBy(nodeSequenceComparer);
}
我们必须记住的一点是,您的属性元素的值可能为null(毕竟,您没有指定不是这种情况)

公共布尔等于(IEnumerable x,IEnumerable y)
{
if(x==null)返回y==null;//如果两者都为null,则返回true
if(y==null)返回false;//false,因为x不是null
//优化:如果x和y是相同的对象,则为true;如果类型不同,则为false
if(Object.ReferenceEquals(x,y)返回true;
如果(x.GetType()!=y.GetType())返回false;
返回x.SequenceEquals(y,这个.CNodeComparer);
}
您写道:

我想按所有元素对它进行分组

Alex给出的解决方案将只按有限数量的元素分组。您说过要按所有元素分组,即使您有一个包含100个元素的CNode。此外:如果其中一个CNode的属性元素等于null,他的解决方案也会崩溃

因此,让我们创建一个满足您需求的解决方案

返回值将是一个组序列,其中每个组都有一个键,这是一个CNODE序列。组中的所有元素都是源CNODE,其属性元素等于键

equal是指SequenceEqual。所以元素[0]==键[0]和元素[1]==键[1],等等

当然,您想确定元素[0]何时等于键[0]:您想通过引用进行比较(同一对象)?或者如果两个CNODE具有相同的属性值,那么它们是否相等?或者您想指定一个
IEqualityComparer
,以便您可以看到如果它们具有相同的名称或Id,那么它们是相等的

// overload without IEqualityComparer, calls the overload with IEqualityComparer:
IEnumerable<IGrouping<IEnumerable<Cnode>, CNode>> GroupBy(
    this IEnumerable<CNode> cNodes)
{
    return GroupBy(cNodes, null);
}

// overload with IEqualityComparer; use default CNode comparer if paramer equals null
IEnumerable<IGrouping<IEnumerable<Cnode>, CNode>> GroupBy(
    this IEnumerable<CNode> cNodes,
    IEqualityComparer<CNode> cNodeComparer)
{
    // TODO: check cNodes != null
    if (cNodeComparer == null) cNodeComparer = EqualityComparer<CNode>.Default;

    CNodeSequenceComparer nodeSequenceComparer = new CNodeSequenceComparer()
    {
        CNodeComparer = cNodeComparer,
    }
    return sequenceComparer.GroupBy(nodeSequenceComparer);
}
我们必须记住的一点是,您的属性元素的值可能为null(毕竟,您没有指定不是这种情况)

公共布尔等于(IEnumerable x,IEnumerable y)
{
if(x==null)返回y==null;//如果两者都为null,则返回true
if(y==null)返回false;//false,因为x不是null
//优化:如果x和y是相同的对象,则为true;如果类型不同,则为false
if(Object.ReferenceEquals(x,y)返回true;
如果(x.GetType()!=y.GetType())返回false;
返回x.SequenceEquals(y,这个.CNodeComparer);
}

Use node.Take(5)@jdweng没有帮助。我想你需要SelectMany var results=cNodes.SelectMany(x=>x.Elements.ToList();所有元素集合的大小都一样吗?@alexanderpetrov是的,它们的大小都一样。Use node.Take(5)@jdweng没有帮助。我想你需要SelectMany var results=cNodes.SelectMany(x=>x.Elements)托利斯先生();是否所有元素集合都具有相同的大小?@alexanderpetrov是的,它们具有相同的大小。如果其中一个CNODE的元素值为空,则此操作将崩溃。毕竟:没有指定所有CNODE都具有非空元素。如果其中一个CNODE的元素值为空,则此操作将崩溃。毕竟:没有指定所有CNODE都具有空值e非空元素。Alex给出的解决方案将只按有限数量的元素分组。实际上
cNodes.GroupByElements()
按所有元素分组,其中所有元素都意味着最短序列中的许多元素。当然,您不希望元素具有序列[1,2]和序列[1,2,3,4,5,6,7,8]要在同一个组中结束,可以将任意数字传递给cNodes.GroupByElements(count)或将公共静态IEnumerable GroupByElements(此IEnumerable节点)=>nodes.GroupByElements(nodes.Min(node=>node.Elements.count))更改为公共静态IEnumerable GroupByElements(此IEnumerable节点)=>nodes.GroupByElements(nodes.Max(node=>node.Elements.Count))无论如何,@Cotur在他对这个问题的评论中确认了集合的大小是相同的。Alex给出的解决方案将只按有限数量的元素分组。实际上
cNodes.GroupByElements()
按所有元素分组,其中all表示最短序列中的多个元素。您肯定不希望序列为[1,2]和序列为[1,2,3,4,5,6,7,8]的元素最终位于同一组中,是吗?您可以将任何数字传递给cNodes。GroupByElements(count)或更改公共静态IEnumerable GroupByElements(此IEnumerable节点)=>nodes.GroupByElements(nodes.Min(node=>node.Elements.Count))到公共静态IEnumerable GroupByElements(此IEnumerable节点)=>nodes.GroupByElements(nodes.Max(node=>node.Elements.Count)),总之,@C
        Group by 2:
0, 0, 1, 1, 1
0, 0, 0, 1, 1
0, 0, 0, 0
0, 0, 0, 0

0, 1, 1, 0
0, 1, 1, 0, 0

        Group by 3:
0, 0, 1, 1, 1

0, 0, 0, 1, 1
0, 0, 0, 0
0, 0, 0, 0

0, 1, 1, 0
0, 1, 1, 0, 0

        Group by all:
0, 0, 1, 1, 1

0, 0, 0, 1, 1

0, 1, 1, 0
0, 1, 1, 0, 0

0, 0, 0, 0
0, 0, 0, 0
// overload without IEqualityComparer, calls the overload with IEqualityComparer:
IEnumerable<IGrouping<IEnumerable<Cnode>, CNode>> GroupBy(
    this IEnumerable<CNode> cNodes)
{
    return GroupBy(cNodes, null);
}

// overload with IEqualityComparer; use default CNode comparer if paramer equals null
IEnumerable<IGrouping<IEnumerable<Cnode>, CNode>> GroupBy(
    this IEnumerable<CNode> cNodes,
    IEqualityComparer<CNode> cNodeComparer)
{
    // TODO: check cNodes != null
    if (cNodeComparer == null) cNodeComparer = EqualityComparer<CNode>.Default;

    CNodeSequenceComparer nodeSequenceComparer = new CNodeSequenceComparer()
    {
        CNodeComparer = cNodeComparer,
    }
    return sequenceComparer.GroupBy(nodeSequenceComparer);
}
class CNodeSequenceComparer : IEqualityComparer<IEnumerable<CNode>>
{
    public IEqualityComparer<CNode> CNodeComparer {get; set;}
    public bool Equals(IEnumerable<CNode> x, IEnumerable<CNode> y)
    {
        // returns true if same sequence, using CNodeComparer
        // TODO: implement
    }
}
public bool Equals(IEnumerable<CNode> x, IEnumerable<CNode> y)
{
    if (x == null) return y == null; // true if both null
    if (y == null) return false;     // false because x not null

    // optimizations: true if x and y are same object; false if different types
    if (Object.ReferenceEquals(x, y) return true;
    if (x.GetType() != y.GetType()) return false;

    return x.SequenceEquals(y, this.CNodeComparer);
}