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);
}