可以说我收集了n
工人.可以说有3个:
John Adam Mark
我想知道他们什么时候打扫办公室.如果我设置int cleanDays = 3
它将是这样的:
//Day of month;worker 1;John 2;John 3;John 4;Adam 5;Adam 6;Adam 7;Mark 8;Mark 9;Mark 10;John 11;John . . .
如果我设置cleanDays = 1
它将是:
1;John 2;Adam 3;Mark 4;John 5;Adam . . .
等等.
我已经管理过这样的事情:
int cleanDays = 6; for (int day=1; day<30;day++) { //for each day int worker = (day-1 % cleanDays)%workers.Count; //get current worker (starting from index 0) for (int times=0; times< cleanDays; times++) //worker do the job `cleanDays` times Console.WriteLine(day++ + ";" +workers[worker].Name); }
这不能正常工作,因为它给了我34天的时间.因为day++
在第一个循环.但如果我day++
从第一个循环中删除:
for (int day=1; day<30;) { //for each day int worker = (day-1 % cleanDays)%workers.Count; //get current worker (starting from index 0) for (int times=0; times< cleanDays; times++) //worker do the job `cleanDays` times Console.WriteLine(day++ + ";" +workers[worker].Name); }
它只给第一个工人输出.当我调试时,我看到了:
int worker = (day-1 % cleanDays)%workers.Count;
并且每次worker
都等于0
.这意味着:
(20-1%6)%3
等于0
.为什么会这样?
更新:我只是更仔细地阅读你的问题,并意识到你根本没有询问实际的代码.你真正的问题是:
这意味着:(20-1%6)%3等于0.为什么会发生这种情况?
首先,它没有. (20-1%6)%3
是1.但逻辑仍然是错误的,因为你的括号在错误的地方.你打算写
int worker = (day - 1) % cleanDays % workers.Count;
请记住,乘法,除法和余数运算符都优先于减法. a + b * c
是a + (b * c)
,不是(a + b) * c
.同样是真正的-
和%
. a - b % c
是a - (b % c)
,不是(a - b) % c
.
但我仍然支持我的原始答案:你可以通过编写一个代表你的序列操作的查询来完全消除这个问题,而不是一个容易出错的复杂算法的循环.
原始答案如下.
Dmitry Bychenko的解决方案非常好,但我们可以改进它; 这里不需要模运算.我们可以直接从中选择多个,而不是索引到worker数组中:
var query = Enumerable.Repeat( workers.SelectMany(worker => Enumerable.Repeat(worker, cleanDays)), 1000) .SelectMany(workerseq => workerseq) .Select((worker, index) => new { Worker = worker, Day = index + 1}) .Take(30); foreach(var x in query) Console.WriteLine($"Day {x.Day} Worker {x.Worker}");
确保您了解此查询的工作原理,因为这些是LINQ的核心操作.我们采取一系列工人,
{A, B, C}
这被投射到一系列序列上:
{ {A, A}, {B, B}, {C, C} }
这是扁平的:
{A, A, B, B, C, C}
然后我们重复一千次:
{ { A, A, B, B, C, C }, { A, A, B, B, C, C }, ... }
然后压平序列序列:
{ A, A, B, B, C, C, A, A, B, B, C, C, ... }
然后我们选择带有索引到该展平的序列以产生一系列日,工作者对.
{ {A, 1}, {A, 2}, {B, 3}, {B, 4}, ... }
然后采取前30个.然后我们执行查询并打印结果.
现在,你可能会说这不是效率低下的吗?如果我们有4个工人,我们每个工作5天,然后我们重复1000次; 制作一个5 x 4 x 1000 = 20000项的序列,但我们只需要前30个.
你看到那个逻辑出了什么问题吗?
LINQ序列是懒惰构造的.因为Take(30)
我们从不构建超过30对.我们可以重复一百万次; 无所谓.你说Take(30)
并且序列结构将在你打印30个之后停止构建更多项目.
但不要止步于此.问问自己如何进一步改进此代码.
整数天的位数似乎有点狡猾.当然你想要的是实际日期.
var start = new DateTime(2017, 1, 1);
现在我们可以选择日期,而不是选择数字:
... .Select((worker, index) => new { Worker = worker, Day = start.AddDays(index)}) ...
这里的主要内容是什么?
而不是乱搞循环和奇怪的算术,只需构建代表你想要的形状的查询.你想要什么?重复每个工人n次.好的,那么你的程序中应该有一行说明Repeat(worker, n)
,现在你的程序看起来像它的规范.现在你的程序更可能是正确的.等等.
为作业使用正确的数据类型.想要代表日期?使用DateTime
,而不是int
.