当前位置:  开发笔记 > 编程语言 > 正文

解决分配的其他方法

如何解决《解决分配的其他方法》经验,为你挑选了1个好方法。

可以说我收集了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.为什么会这样?



1> Eric Lippert..:

更新:我只是更仔细地阅读你的问题,并意识到你根本没有询问实际的代码.你真正的问题是:

这意味着:(20-1%6)%3等于0.为什么会发生这种情况?

首先,它没有. (20-1%6)%3是1.但逻辑仍然是错误的,因为你的括号在错误的地方.你打算写

int worker = (day - 1) % cleanDays % workers.Count;

请记住,乘法,除法和余数运算符都优先于减法. a + b * ca + (b * c),不是(a + b) * c.同样是真正的-%. a - b % ca - (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.

推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有