Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.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# 我怎样才能使用;Linq to Objects“;将一组连续的日期放在一个组中?_C#_Linq - Fatal编程技术网

C# 我怎样才能使用;Linq to Objects“;将一组连续的日期放在一个组中?

C# 我怎样才能使用;Linq to Objects“;将一组连续的日期放在一个组中?,c#,linq,C#,Linq,我有一个棘手的问题要写。我目前正在写一些讨厌的for循环来解决这个问题,但我很想知道Linq是否能帮我解决这个问题 我有: struct TheStruct { public DateTime date {get; set;} //(time portion will always be 12 am) public decimal A {get; set;} public decimal B {get; set;} } 以及包含这些结构的列表。假设是这样订购的: List<TheS

我有一个棘手的问题要写。我目前正在写一些讨厌的for循环来解决这个问题,但我很想知道Linq是否能帮我解决这个问题

我有:

struct TheStruct
{
 public DateTime date {get; set;} //(time portion will always be 12 am)
 public decimal A {get; set;}
 public decimal B {get; set;}
}
以及包含这些结构的列表。假设是这样订购的:

List<TheStruct> orderedList = unorderedList.OrderBy(x => x.date).ToList();
List orderedList=unorderedList.OrderBy(x=>x.date.ToList();
如果将orderedList结构日期放在一个集合中,它们将始终与日期相邻。。也就是说,如果列表中最晚的日期是2011/01/31,而列表中最早的日期是2011/01/01,那么您会发现该列表将包含31个项目,每个项目对应于1月份的一个日期

好的,我要做的是对列表项进行分组,以便:

  • 组中的每个项目必须包含相同的十进制a值和十进制B值
  • 如果日期值按顺序排列,则组中的日期值必须形成一组连续的日期
  • 如果将每个组中的项目总和相加,则总数将等于原始列表中的项目数(或者可以说具有特定日期的结构不能属于多个组)
  • 有Linq大师知道怎么做吗


    谢谢

    您可以使用(见下文)按顺序对相邻项目进行分组:

    例如:

    (1,1)2011-01-01\
    (1,1)2011-01-02>第一组
    (1,1) 2011-01-03 __/
    (2,1) 2011-01-04   \
    (2,1)2011-01-05>第2组
    (2,1) 2011-01-06 __/
    (1,1) 2011-01-07   \
    (1,1)2011-01-08>第三组
    (1,1) 2011-01-09 __/
    (1,1) 2011-02-01   \
    (1,1)2011-02-02>第4组
    (1,1) 2011-02-03 __/
    
    扩展方法:

    静态IEnumerable组(
    此IEnumerable源,Func(相邻)
    {
    var g=新列表();
    foreach(源中的变量x)
    {
    如果(g.Count!=0&&!相邻(g,x))
    {
    收益率g;
    g=新列表();
    }
    g、 加(x);
    }
    收益率g;
    }
    
    如果我能很好地理解你,一个简单的小组成员就可以做到:

    var orderedList = unorderedList.OrderBy(o => o.date).GroupBy(s => new {s.A, s.B});
    
    就这样。要打印结果,请执行以下操作:

          foreach (var o in orderedList) {                 
                Console.WriteLine("Dates of group {0},{1}:", o.Key.A, o.Key.B);
                foreach(var s in o){
                    Console.WriteLine("\t{0}", s.date);
                }
            }
    
    输出如下所示:

    Dates of group 2,3:
        02/12/2011
        03/12/2011
    Dates of group 4,3:
        03/12/2011
    Dates of group 1,2:
        04/12/2011
        05/12/2011
        06/12/2011
    
    希望这有帮助。 干杯

    这里是“最复杂的方法”的条目:

    公共静态类结构管理器
    {
    公共静态IEnumerable OrganizeWithoutGaps(此IEnumerable someStructs)
    {
    var somestructsalist=someStructs.ToList();
    var lastValuesSeen=新元组(someStructsAsList[0].A,someStructsAsList[0].B);
    var currentList=新列表();
    返回可枚举
    .Range(0,someStructsAsList.Count)
    托利斯先生()
    .选择(i=>
    {
    var current=someStructsAsList[i];
    if(lastValuesSeen.Equals(新元组(current.A,current.B)))
    currentList.Add(当前);
    其他的
    {
    lastValuesSeen=新元组(当前.A,当前.B);
    var oldList=currentList;
    currentList=新列表(new[]{current});
    返回新元组(lastValuesSeen.Item1、lastValuesSeen.Item2、oldList);
    }
    返回null;
    })
    。其中(i=>i!=null);
    }
    //要测试:
    公共静态无效测试()
    {
    var r=新的随机变量();
    var sampleData=Enumerable.Range(1,31)。选择(i=>newmystruct{A=r.Next(0,2),B=r.Next(0,2),date=newdatetime(2011,12,i)});
    var sortedData=sampleData.OrganizeWithoutGaps();
    Console.Out.WriteLine(“示例数据:”);
    sampleData.ForEach(s=>Console.Out.WriteLine(“{0}=({1},{2})”,s.date,s.A,s.B));
    Console.Out.WriteLine(“输出:”);
    sortedData.ToList().ForEach(s=>Console.Out.WriteLine(“({0},{1})={2}”,s.Item1,s.Item2,String.Join(“,”,s.Item3.Select(st=>st.date)));
    }
    }
    
    假设您有12月1日至12月10日的值(1,1),12月11日至12月20日的值(1,2),以及12月21日至12月31日的值(1,1),您想要两组还是三组输出?如果是两个,您希望(1,1)日期之间有一个间隔,还是缺少日期的默认值a和B?我想要三组。如果存在间隙,则无法形成连续日期集。如果我在间隙中用默认值填充A和B,那么所有组中的项目都会比我最初使用的多,因此您希望
    GroupBy
    A
    B
    。然后,在每个组内,是否按订购人
    日期
    ?或者你也需要它们是不同的吗?我需要按A和B分组,但困难的是我如何告诉Linq返回的组中的日期必须是连续的?这似乎是我想要的。我不知道的是如何将“相邻”日期分组。我要试试看!这将起作用,但我认为它可能效率很低,因为在
    相邻的
    函数中使用了IEnumerable。如果我没有弄错的话,这将导致对那些.Last()调用的重复列表迭代,这将类似于2N!迭代,如果您的所有项都有相同的A和B。也就是说,它比我的解决方案优雅50倍:-)@ChrisShain:如果我没有弄错的话,最后一个()方法非常聪明,可以检查枚举是否是IList。如果是,它将使用
    source[source.Count-1]
    获取最后一项,而不是迭代整个序列。只需在reflector中进行检查-您完全正确。我收回我先前的评论:-)如果1,2发生在第1、2和3天,以及第6、7和9天,这会返回两组1,2吗?这不起作用,它只按数字分组,不管日期是什么。是的,它按数字分组。我不太明白你的要求。你一定是很快就想到了那个@国际广播公司
          foreach (var o in orderedList) {                 
                Console.WriteLine("Dates of group {0},{1}:", o.Key.A, o.Key.B);
                foreach(var s in o){
                    Console.WriteLine("\t{0}", s.date);
                }
            }
    
    Dates of group 2,3:
        02/12/2011
        03/12/2011
    Dates of group 4,3:
        03/12/2011
    Dates of group 1,2:
        04/12/2011
        05/12/2011
        06/12/2011
    
    public static class StructOrganizer
    {
        public static IEnumerable<Tuple<Decimal, Decimal, IEnumerable<MyStruct>>> OrganizeWithoutGaps(this IEnumerable<MyStruct> someStructs)
        {
            var someStructsAsList = someStructs.ToList();
            var lastValuesSeen = new Tuple<Decimal, Decimal>(someStructsAsList[0].A, someStructsAsList[0].B);
            var currentList = new List<MyStruct>();
            return Enumerable
                .Range(0, someStructsAsList.Count)
                .ToList()
                .Select(i =>
                            {
                                var current = someStructsAsList[i];
                                if (lastValuesSeen.Equals(new Tuple<Decimal, Decimal>(current.A, current.B)))
                                    currentList.Add(current);
                                else
                                {
                                    lastValuesSeen = new Tuple<decimal, decimal>(current.A, current.B);
                                    var oldList = currentList;
                                    currentList = new List<MyStruct>(new [] { current });
                                    return new Tuple<decimal, decimal, IEnumerable<MyStruct>>(lastValuesSeen.Item1, lastValuesSeen.Item2, oldList);
                                }
                                return null;
                            })
                .Where(i => i != null);
        }
    
        // To Test:
        public static void Test()
        {
            var r = new Random();
    
            var sampleData = Enumerable.Range(1, 31).Select(i => new MyStruct {A = r.Next(0, 2), B = r.Next(0, 2), date = new DateTime(2011, 12, i)}).OrderBy(s => s.date).ToList();
            var sortedData = sampleData.OrganizeWithoutGaps();
    
            Console.Out.WriteLine("Sample Data:");
            sampleData.ForEach(s => Console.Out.WriteLine("{0} = ({1}, {2})", s.date, s.A, s.B));
            Console.Out.WriteLine("Output:");
            sortedData.ToList().ForEach(s => Console.Out.WriteLine("({0}, {1}) = {2}", s.Item1, s.Item2, String.Join(", ", s.Item3.Select(st => st.date))));
        }
    }