【问题标题】:Select only two elements from an array for each element from antoher array对于另一个数组中的每个元素,仅从一个数组中选择两个元素
【发布时间】:2020-07-06 18:31:19
【问题描述】:

所以我在一个对象中有 10 个不同的元素(我称他们为工人),我试图给他们两天时间(每个人工作)。天数不能连续。

我设法创建了一个生成两个不同且不连续的日子的函数

 getTwoNonConsecutiveDays = () => {
    let saved = [];
    var days = require('./weeks.json');
    let randomIndex = (days) => {
      return Math.floor(Math.random() * days.length);
    };

    let randomPair = (days) => {
      var index1 = randomIndex(days),
        index2;
      do {
        index2 = randomIndex(days);
      } while (
        index1 == index2 ||
        index1 == index2 + 1 ||
        index1 == index2 - 1
      );
      return [days[index1], days[index2]];
    };
     ;
    saved.push(...randomPair(days));
   return JSON.stringify(randomPair(days))
  };

还有一个选择所有工人并给每个工人两天的功能

  getWorkers = () => {
    var workers = require('./workers.json');
    return  workers.map((a) => 
    
    <View>
      <Text>{this.getTwoNonConsecutiveDays()}</Text>
       <Text key={a.id.toString()}>{a.id}</Text></View>
   );
  };

当前测试的输出是:

 [{"id":3,"name":"Wednesday","workers":[]},{"id":1,"name":"Monday","workers":[]}]worker name is :1
[Mon Jul 06 2020 21:28:36.607]  LOG      [{"id":4,"name":"Thursday","workers":[]},{"id":1,"name":"Monday","workers":[]}]worker name is :2
[Mon Jul 06 2020 21:28:36.608]  LOG      [{"id":3,"name":"Wednesday","workers":[]},{"id":5,"name":"Friday","workers":[]}]worker name is :3
[Mon Jul 06 2020 21:28:36.608]  LOG      [{"id":1,"name":"Monday","workers":[]},{"id":4,"name":"Thursday","workers":[]}]worker name is :4
[Mon Jul 06 2020 21:28:36.609]  LOG      [{"id":4,"name":"Thursday","workers":[]},{"id":1,"name":"Monday","workers":[]}]worker name is :5
[Mon Jul 06 2020 21:28:36.610]  LOG      [{"id":3,"name":"Wednesday","workers":[]},{"id":5,"name":"Friday","workers":[]}]worker name is :6
[Mon Jul 06 2020 21:28:36.612]  LOG      [{"id":1,"name":"Monday","workers":[]},{"id":3,"name":"Wednesday","workers":[]}]worker name is :7
[Mon Jul 06 2020 21:28:36.613]  LOG      [{"id":5,"name":"Friday","workers":[]},{"id":2,"name":"Tuesday","workers":[]}]worker name is :8
[Mon Jul 06 2020 21:28:36.614]  LOG      [{"id":3,"name":"Wednesday","workers":[]},{"id":1,"name":"Monday","workers":[]}]worker name is :9
[Mon Jul 06 2020 21:28:36.615]  LOG      [{"id":4,"name":"Thursday","workers":[]},{"id":1,"name":"Monday","workers":[]}]worker name is :10

现在的问题是,一天不能由两个以上的工人占用。我想要的结果是每个工人会有两天的时间,但每天不会为单个工人选择超过两次。工人 id 可以在每个指定为数字的输出的最后看到。

【问题讨论】:

  • 如果您发布输入数据和预期输出数据而不是不起作用的功能,这将有所帮助。
  • 我希望有一个列表,每天最多只能找到两个工人。
  • days 数组中的项目是否唯一?
  • '...我设法创建了...' 您似乎在使用上一个问题中的the answer,甚至懒得接受。无论如何,这不是一个好的选择,因为在找到合适的配对之前进行猜测是解决问题的过度方法。

标签: javascript arrays reactjs react-native


【解决方案1】:

我可以通过一些作弊来做到这一点。 . .代码中有需要解释的注释,但总结了它的 3 个部分:首先每天随机分配 1 个工人,然后每天找出可用的选项,最后分配这些选项。我无法让第 3 部分成功完成 100% 的时间(~98%),所以如果函数失败,我会递归运行该函数。请注意,这不是直接基于您的代码,而是总体上演示算法。

//mock values
const days = {
  "Day1": [],
  "Day2": [],
  "Day3": [],
  "Day4": [],
  "Day5": [],
  "Day6": [],
  "Day7": [],
  "Day8": [],
  "Day9": [],
  "Day10": []
}
//mock values
const workers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

//assign a worker to each day at random;
function partA(workers, days) {
  //copy made for push mutation
  const daysCopy = { ...days
  };
  //copy made for splice mutation
  const workersCopy = [...workers];
  //a worker is selected at random, then spliced from the worker array to prevent being selected again
  Object.keys(daysCopy).forEach(key => {
    const random = Math.floor(Math.random() * workersCopy.length);
    daysCopy[key] = [workersCopy.splice(random,1)[0]];
  })      
  return partB(workers, daysCopy);
}

//determine what workers are available for each remaining slot
function partB(workers, days) {
  //create an object map of available workers
  const workerMap = {};
  //for each day check who the current, previous, and next day's worker is, then add all others to object map
  Object.keys(days).forEach((key, index) => {
    const current = days[key][0];
    const prev = days[Object.keys(days)[index - 1]] ? days[Object.keys(days)[index - 1]][0] : null;
    const next = days[Object.keys(days)[index + 1]] ? days[Object.keys(days)[index + 1]][0] : null;
    const allowed = workers.filter(worker => [current, prev, next].indexOf(worker) < 0);
    workerMap[key] = allowed;
  })
  //pass daysCopy and workerMap to final part
  return partC(days, workerMap)
}

//randomly assign remaining workers
function partC(days, workerMap) {
  //create copy for push mutation
  const daysCopy = { ...days
  };
  //create copy for delete mutation
  let mapCopy = { ...workerMap
  };
  //while there remains available workers
  while (Object.keys(mapCopy).length) {
    //store keys for days with available workers
    const keys = Object.keys(mapCopy);
    //create object map for length of available workers per day
    const lengths = {};
    Object.keys(mapCopy).forEach(key => {
      lengths[key] = mapCopy[key].length;
    })
    //find the day with the least amount of options as this guarantees less chance of failure
    const shortestVal = Object.values(lengths).sort((a, b) => a - b)[0];
    const shortestKey = keys.find(key => lengths[key] === shortestVal)

    //randomly select an available option for the shortest day
    const options = mapCopy[shortestKey];
    const random = Math.floor(Math.random() * options.length);
    const selection = options[random];

    //this is where I cheat; 
    //if the assignment fails, it will recursively call itself; this occurs about 2% of the time
    if (typeof selection === "undefined") return partC(days, workerMap);
    //otherwise push the selection as the second worker for the day
    daysCopy[shortestKey] = [...daysCopy[shortestKey], selection];
    //remove that worker as an available option for all other days
    keys.forEach(key => {
      mapCopy[key] = mapCopy[key].filter(worker => worker !== selection);
    })
    //delete the resolved day from the availability map
    delete mapCopy[shortestKey];
  }


  //return days with assigned workers
  return daysCopy;
}

console.log((partA(workers, days)));

【讨论】:

    【解决方案2】:

    如果你想给每个人增加两天的工作时间,并且每天只允许两个工人,那么就会出现一个问题:10 个工人每天分配给两个不重复,一周必须是 10 天。 但我假设一周中的几天数组只有 7 天,但如果它有更多天,例如,它有两个半星期,一切都很好。 也就是说,根据您的问题调整我提出的这个解决方案:

    // you can add as many consecutive days as you want
    let weekDays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
    // number of workers per day, in this case, it is doubled for two per day
    let doubleDays = [...weekDays, ...weekDays];
    
    let workers = [{id: 1}, {id: 2}];
    
    const getTwoNonConsecutiveDays = () => {
      let randomIndex = (days) => {
        return Math.floor(Math.random() * days.length);
      };
    
      let index = randomIndex(doubleDays), index2;
      let indexWeekDay = weekDays.indexOf(doubleDays[index]), indexWeekDay2;
    
      doubleDays.splice(index, 1);
      let array = doubleDays.filter((filter) => !(filter === weekDays[indexWeekDay] || filter === weekDays[indexWeekDay === 0 ? weekDays.length - 1 : indexWeekDay - 1] || filter === weekDays[indexWeekDay === weekDays.length - 1 ? 0 : indexWeekDay + 1]));
    
      index2 = randomIndex(array);
      indexWeekDay2 = weekDays.indexOf(array[index2]);
      doubleDays.splice(index2, 1);
      return [weekDays[indexWeekDay], weekDays[indexWeekDay2]]
    };
    
    console.log(workers.map(() => (getTwoNonConsecutiveDays())));

    【讨论】:

    • - 一名工程师一天最多可以轮班半天。 - 每个工程师应该在任何 2 周内完成一整天的支持。 - 工程师不能连续工作半天班。
    猜你喜欢
    • 1970-01-01
    • 2015-08-15
    • 2017-02-08
    • 2013-11-02
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多