Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/309.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#_Linq_Data Structures - Fatal编程技术网

C# 分组的最佳方式是什么?

C# 分组的最佳方式是什么?,c#,linq,data-structures,C#,Linq,Data Structures,所以最近我遇到了一个问题,我的团队和我需要获取一个对象列表,并按条件对它们进行分组,然后按更多条件分组,然后再按更多条件分组,依此类推7级左右。经过几天的思考,我终于想出了一种树形结构,尽管每个级别都是手动定义的(主要是为了便于阅读,因为一旦编程,它就会被固定下来)。最好的处理方法是什么?如果可能,为什么? 这是我到目前为止使用的随机整数列表。检查的顺序是:可被2整除,可被3整除,可被5整除(尽管条件的顺序与要求无关): 下面是随机整数列表和TopNode类的代码 Random rand = n

所以最近我遇到了一个问题,我的团队和我需要获取一个对象列表,并按条件对它们进行分组,然后按更多条件分组,然后再按更多条件分组,依此类推7级左右。经过几天的思考,我终于想出了一种树形结构,尽管每个级别都是手动定义的(主要是为了便于阅读,因为一旦编程,它就会被固定下来)。最好的处理方法是什么?如果可能,为什么? 这是我到目前为止使用的随机整数列表。检查的顺序是:可被2整除,可被3整除,可被5整除(尽管条件的顺序与要求无关):

下面是随机整数列表和TopNode类的代码

Random rand = new Random();
List<int> ints = new List<int>();
for (int i = 0; i < 10; i++)
{
   ints.Add(rand.Next(0, 10000001));
}

TopNode node = new TopNode(ints);
Random rand=new Random();
List ints=新列表();
对于(int i=0;i<10;i++)
{
整数加(下一个兰特(0100000001));
}
TopNode=新TopNode(ints);
下面是顶级节点类的其余代码

public class TopNode 
{ 
    public Even Even { get; set; }
    public Odd Odd { get; set; }
    public TopNode(List<int> ints)
    {
        var even = ints.Where(x => x % 2 == 0).ToList();
        var odd = ints.Where(x => x % 2 != 0).ToList();
        if (even.Count > 0)
        {
            Even = new Even(even);
        }
        if (odd.Count > 0)
        {
            Odd = new Odd(odd);
        }
    }
} 

public class Even {
    public Mulitple3 Mulitple3 { get; set; }
    public NotMulitple3 NotMulitple3 { get; set; }
    public Even(List<int> ints)
    {
        var multiple = ints.Where(x => x % 3 == 0).ToList();
        var not = ints.Where(x => x % 3 != 0).ToList();
        if (multiple.Count > 0)
        {
            Mulitple3 = new Mulitple3(multiple);
        }
        if (not.Count > 0)
        {
            NotMulitple3 = new NotMulitple3(not);
        }
    }
} 

public class Odd {
    public Mulitple3 Mulitple3 { get; set; }
    public NotMulitple3 NotMulitple3 { get; set; }
    public Odd(List<int> ints)
    {
        var multiple = ints.Where(x => x % 3 == 0).ToList();
        var not = ints.Where(x => x % 3 != 0).ToList();
        if (multiple.Count > 0)
        {
            Mulitple3 = new Mulitple3(multiple);
        }
        if (not.Count > 0)
        {
            NotMulitple3 = new NotMulitple3(not);
        }
    }
}

public class Mulitple3
{
    public Multiple5 Multiple5 { get; set; }
    public NotMultiple5 NotMultiple5 { get; set; }
    public Mulitple3(List<int> ints)
    {
        var multiple = ints.Where(x => x % 5 == 0).ToList();
        var not = ints.Where(x => x % 5 != 0).ToList();
        if (multiple.Count > 0)
        {
            Multiple5 = new Multiple5(multiple);
        }
        if (not.Count > 0)
        {
            NotMultiple5 = new NotMultiple5(not);
        }
    }
}

public class NotMulitple3
{
    public Multiple5 Multiple5 { get; set; }
    public NotMultiple5 NotMultiple5 { get; set; }
    public NotMulitple3(List<int> ints)
    {
        var multiple = ints.Where(x => x % 5 == 0).ToList();
        var not = ints.Where(x => x % 5 != 0).ToList();
        if (multiple.Count > 0)
        {
            Multiple5 = new Multiple5(multiple);
        }
        if (not.Count > 0)
        {
            NotMultiple5 = new NotMultiple5(not);
        }
    }
}

public class Multiple5
{
    public List<int> ints { get; set; }
    public Multiple5(List<int> ints)
    {
        this.ints = ints;
    }
}

public class NotMultiple5
{
    public List<int> ints { get; set; }
    public NotMultiple5(List<int> ints)
    {
        this.ints = ints;
    }
}
公共类TopNode
{ 
公共偶数{get;set;}
公共奇数{get;set;}
公共TopNode(列表整数)
{
var even=int.Where(x=>x%2==0.ToList();
var odd=int.Where(x=>x%2!=0).ToList();
如果(偶数计数>0)
{
偶数=新偶数(偶数);
}
如果(奇数计数>0)
{
奇数=新的奇数(奇数);
}
}
} 
甚至是公共阶层{
公共Mulitple3 Mulitple3{get;set;}
public NotMulitple3 NotMulitple3{get;set;}
公共偶数(列表整数)
{
var multiple=int.Where(x=>x%3==0.ToList();
var not=int.Where(x=>x%3!=0).ToList();
如果(multiple.Count>0)
{
Mulitple3=新的Mulitple3(多个);
}
如果(非计数>0)
{
NotMulitple3=新NotMulitple3(非);
}
}
} 
公共类奇数{
公共Mulitple3 Mulitple3{get;set;}
public NotMulitple3 NotMulitple3{get;set;}
公共奇数(列表整数)
{
var multiple=int.Where(x=>x%3==0.ToList();
var not=int.Where(x=>x%3!=0).ToList();
如果(multiple.Count>0)
{
Mulitple3=新的Mulitple3(多个);
}
如果(非计数>0)
{
NotMulitple3=新NotMulitple3(非);
}
}
}
公共类Mulitple3
{
公共倍数5倍数5{get;set;}
public NotMultiple5 NotMultiple5{get;set;}
公共多功能3(列表整数)
{
var multiple=int.Where(x=>x%5==0.ToList();
var not=int.Where(x=>x%5!=0).ToList();
如果(multiple.Count>0)
{
倍数5=新倍数5(倍数);
}
如果(非计数>0)
{
NotMultiple5=新的NotMultiple5(非);
}
}
}
公共类NotMulitple3
{
公共倍数5倍数5{get;set;}
public NotMultiple5 NotMultiple5{get;set;}
公共信息3(列表整数)
{
var multiple=int.Where(x=>x%5==0.ToList();
var not=int.Where(x=>x%5!=0).ToList();
如果(multiple.Count>0)
{
倍数5=新倍数5(倍数);
}
如果(非计数>0)
{
NotMultiple5=新的NotMultiple5(非);
}
}
}
公共类倍数5
{
公共列表整数{get;set;}
公共倍数5(列表整数)
{
this.ints=ints;
}
}
公共类非倍数5
{
公共列表整数{get;set;}
公共非倍数5(列表整数)
{
this.ints=ints;
}
}

我还创建了一个树类,但我使用一个类来保存每个条件,并使用一个条件数组来处理分组。每个条件都应返回一个
int
,以创建分组。然后,树类可以逐步通过条件对每个级别进行分组。为了使树统一,我在每个级别保留了一个成员列表,然后将其拆分为下一个级别

public class Condition<T> {
    public string[] Values;
    public Func<T, int> Test;

    public Condition(string[] values, Func<T, int> test) {
        Values = values;
        Test = test;
    }
}

public class Level {
    public static Level<T> MakeTree<T>(IEnumerable<T> src, Condition<T>[] conditions) => new Level<T>(src, conditions);
    public static IEnumerable<int> MakeKey<T>(Condition<T>[] conditions, params string[] values) {
        for (int depth = 0; depth < values.Length; ++depth)
            yield return conditions[depth].Values.IndexOf(values[depth]);
    }
}

public class Level<T> {
    public string Value;
    public Level<T>[] NextLevels;
    public List<T> Members;

    public Level(string value, List<T> members) {
        Value = value;
        Members = members;
        NextLevels = null;
    }

    public Level(IEnumerable<T> src, Condition<T>[] conditions) : this("ALL", src.ToList()) => GroupOneLevel(this, 0, conditions);

    public void GroupOneLevel(Level<T> parent, int depth, Condition<T>[] conditions) {
        var condition = conditions[depth];
        var nextLevels = new Level<T>[condition.Values.Length];
        for (int j2 = 0; j2 < condition.Values.Length; ++j2) {
            nextLevels[j2] = new Level<T>(condition.Values[j2], new List<T>());
        }

        for (int j2 = 0; j2 < parent.Members.Count; ++j2) {
            var member = parent.Members[j2];
            nextLevels[condition.Test(member)].Members.Add(member);
        }
        parent.NextLevels = nextLevels;
        if (depth + 1 < conditions.Length)
            for (int j3 = 0; j3 < condition.Values.Length; ++j3)
                GroupOneLevel(nextLevels[j3], depth + 1, conditions);
    }

    public List<T> MembersForKey(IEnumerable<int> values) {
        var curLevel = this;
        foreach (var value in values)
            curLevel = curLevel.NextLevels[value];

        return curLevel.Members;
    }
}

最简单的树就是一个
IEnumerable
,您可以使用
GroupBy
形成它

下面是一个简单的例子,根据2、3和5的整除性将一些整数分组到树中。它打印:

{{{{1,7,23,29},{5}},{{3,9,87,21}}},{{{4,8,34,56}},{{78},{30}}}}

publicstaticvoidmain()
{
int[]input=newint[]{1,3,4,5,7,8,9,23,34,56,78,87,29,21,2*3*5};
//树
var groupedTree=input.GroupBy(x=>x%2==0)
.Select(g=>g.GroupBy(x=>x%3==0)
。选择(h=>h.GroupBy(x=>x%5==0));
Console.WriteLine(显示(groupedTree));
}
//破解代码以转储树
公共静态字符串显示序列(IEnumerable items)=>“{”+string.Join(“,”,items.Cast().Select(x=>Display(x)))+“}”;
公共静态字符串显示(对象项)=>项是否为IEnumerable seq?DisplaySequence(seq):item.ToString();

我的建议是创建一个可以过滤对象的集合类,并返回其自身的实例,以便继续进行更深入的过滤。例如,假设对象的类型为
MyObject

class MyObject
{
    public int Number { get; }
    public MyObject(int number) => this.Number = number;
    public override string ToString() => this.Number.ToString();
}
下面是筛选集合
MyCollection
的一个示例,它支持对
奇数
偶数
倍数3
非倍数3
进行筛选。创建所需的,以避免为永远不会被请求的搜索分配内存:

class MyCollection : IEnumerable<MyObject>
{
    private readonly IEnumerable<MyObject> _source;

    private readonly Lazy<ILookup<bool, MyObject>> _multiple2Lookup;
    private readonly Lazy<MyCollection> _even;
    private readonly Lazy<MyCollection> _odd;

    private readonly Lazy<ILookup<bool, MyObject>> _multiple3Lookup;
    private readonly Lazy<MyCollection> _multiple3;
    private readonly Lazy<MyCollection> _nonMultiple3;

    public MyCollection Even => _even.Value;
    public MyCollection Odd => _odd.Value;

    public MyCollection Multiple3 => _multiple3.Value;
    public MyCollection NonMultiple3 => _nonMultiple3.Value;

    public MyCollection(IEnumerable<MyObject> source)
    {
        _source = source;

        _multiple2Lookup = new Lazy<ILookup<bool, MyObject>>(
            () => _source.ToLookup(o => o.Number % 2 == 0));
        _even = new Lazy<MyCollection>(
            () => new MyCollection(_multiple2Lookup.Value[true]));
        _odd = new Lazy<MyCollection>(
            () => new MyCollection(_multiple2Lookup.Value[false]));

        _multiple3Lookup = new Lazy<ILookup<bool, MyObject>>(
            () => _source.ToLookup(o => o.Number % 3 == 0));
        _multiple3 = new Lazy<MyCollection>(
            () => new MyCollection(_multiple3Lookup.Value[true]));
        _nonMultiple3 = new Lazy<MyCollection>(
            () => new MyCollection(_multiple3Lookup.Value[false]));
    }

    public IEnumerator<MyObject> GetEnumerator() => _source.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
输出:

2,4,8,10,14,16,20


这种方法的一个可能缺点是它允许调用
myObjects.Even.NonMultiple3
myObjects.NonMultiple3.Even
。这两个查询返回相同的结果,但会导致创建冗余查找。

根据问题,NetMage和Theodor的答案正是我想要的。然而,由于我的示例代码中有一个oversite,我忽略了提到有时答案返回的不仅仅是true或false,而是返回的
public static void Main()
{
    int[] input = new int[]{1, 3, 4, 5, 7, 8, 9, 23, 34, 56, 78, 87, 29, 21, 2*3*5};

    // TREE
    var groupedTree = input.GroupBy(x => x % 2 == 0)
        .Select(g => g.GroupBy(x => x % 3 == 0)
        .Select(h => h.GroupBy(x => x % 5 == 0)));

    Console.WriteLine(Display(groupedTree));
}

// Hack code to dump the tree
public static string DisplaySequence(IEnumerable items) => "{" + string.Join(",", items.Cast<object>().Select(x => Display(x))) + "}";
public static string Display(object item) => item is IEnumerable seq ? DisplaySequence(seq) : item.ToString();
class MyObject
{
    public int Number { get; }
    public MyObject(int number) => this.Number = number;
    public override string ToString() => this.Number.ToString();
}
class MyCollection : IEnumerable<MyObject>
{
    private readonly IEnumerable<MyObject> _source;

    private readonly Lazy<ILookup<bool, MyObject>> _multiple2Lookup;
    private readonly Lazy<MyCollection> _even;
    private readonly Lazy<MyCollection> _odd;

    private readonly Lazy<ILookup<bool, MyObject>> _multiple3Lookup;
    private readonly Lazy<MyCollection> _multiple3;
    private readonly Lazy<MyCollection> _nonMultiple3;

    public MyCollection Even => _even.Value;
    public MyCollection Odd => _odd.Value;

    public MyCollection Multiple3 => _multiple3.Value;
    public MyCollection NonMultiple3 => _nonMultiple3.Value;

    public MyCollection(IEnumerable<MyObject> source)
    {
        _source = source;

        _multiple2Lookup = new Lazy<ILookup<bool, MyObject>>(
            () => _source.ToLookup(o => o.Number % 2 == 0));
        _even = new Lazy<MyCollection>(
            () => new MyCollection(_multiple2Lookup.Value[true]));
        _odd = new Lazy<MyCollection>(
            () => new MyCollection(_multiple2Lookup.Value[false]));

        _multiple3Lookup = new Lazy<ILookup<bool, MyObject>>(
            () => _source.ToLookup(o => o.Number % 3 == 0));
        _multiple3 = new Lazy<MyCollection>(
            () => new MyCollection(_multiple3Lookup.Value[true]));
        _nonMultiple3 = new Lazy<MyCollection>(
            () => new MyCollection(_multiple3Lookup.Value[false]));
    }

    public IEnumerator<MyObject> GetEnumerator() => _source.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
var source = Enumerable.Range(1, 20).Select(i => new MyObject(i));
var myObjects = new MyCollection(source);
var filtered = myObjects.Even.NonMultiple3;
Console.WriteLine(String.Join(", ", filtered));
Random rand = new Random();
List<int> ints = new List<int>();
for (int i = 0; i < 10000000; i++)
{
   ints.Add(rand.Next(0, 10000001));
}
string[] conditions = new string[] { "even", "div3", "div5" };
var dynamicSort = new Sorted(ints);

public class Sorted
{
    public List<List<int>> returnVal { get; set; }
    public static List<int> Odd(List<int> ints)
    {
        return ints.Where(x => x % 2 != 0).ToList();
    }
    public static List<int> Even(List<int> ints)
    {
        return ints.Where(x => x % 2 == 0).ToList();
    }
    public static List<int> DivThree(List<int> ints)
    {
        return ints.Where(x => x % 3 == 0).ToList();
    }
    public static List<int> NotDivThree(List<int> ints)
    {
        return ints.Where(x => x % 3 != 0).ToList();
    }
    public static List<int> DivFive(List<int> ints)
    {
        return ints.Where(x => x % 5 == 0).ToList();
    }
    public static List<int> NotDivFive(List<int> ints)
    {
        return ints.Where(x => x % 5 != 0).ToList();
    }

    public Sorted(List<int> ints, string[] conditions)
    {
        returnVal = GetSorted(ints, conditions, 0);
    }
    public List<List<int>> GetSorted(List<int>ints, string[] conditions, int index)
    {
        var sortReturn = new List<List<int>>();
        switch (conditions[index].ToLower()) 
        {
            case "even":
            case "odd":
                {
                    if (index == conditions.Length - 1)
                    {
                        sortReturn.Add(Odd(ints));
                        sortReturn.Add(Even(ints));
                    }
                    else
                    {
                        var i = ++index;
                        sortReturn.AddRange(GetSorted(Odd(ints), conditions, i));
                        sortReturn.AddRange(GetSorted(Even(ints), conditions, i));
                    }
                    break;
                }
            case "div3":
            case "notdiv3":
                {
                    if (index == conditions.Length - 1)
                    {
                        sortReturn.Add(DivThree(ints));
                        sortReturn.Add(NotDivThree(ints));
                    }
                    else
                    {
                        var i = ++index;
                        sortReturn.AddRange(GetSorted(DivThree(ints), conditions, i));
                        sortReturn.AddRange(GetSorted(NotDivThree(ints), conditions, i));
                    }
                    break;
                }
            case "div5":
            case "notdiv5":
                {
                    if (index == conditions.Length - 1)
                    {
                        sortReturn.Add(DivFive(ints));
                        sortReturn.Add(NotDivFive(ints));
                    }
                    else
                    {
                        var i = ++index;
                        sortReturn.AddRange(GetSorted(DivFive(ints), conditions, i));
                        sortReturn.AddRange(GetSorted(NotDivFive(ints), conditions, i));
                    }
                    break;
                }
        }
        return sortReturn;
    }
}