JS-迭代列表中整个列表的有效方法

时间:2018-06-24 03:45:36

标签: javascript loops

在另一个列表中查找项目的最有效算法是什么?让我尝试写一个例子:

  • 我具有以下结构:
    • 雇主:[{"id": 1, "skill": 10},{"id": 2, "skill": 90}];
    • 客户:[{"id": 12, "mood": 5},{"id": 2, "mood": 70}]

该信息由数组表示:

  • 雇主数组:[[1, 10], [2, 90]];
  • 客户数组:[[12, 5], [2, 70]]

在我的情况下,雇主只能与心情 低于其 的客户互动。我的职能回报应该是具有最高互动度的雇主。

我编写了可以执行此规则的函数,但是当我有大量的雇主或客户时,它的运行速度非常慢-完成过程花费了7秒钟以上。

function countEmployersByMoodAtt(operatos, customers) {
    let distribution = [];
    //sort operators by skill so I can guarantee that big skills won't come first
    operatos.sort((a, b) => a[1] - b[1]);

    operatos.forEach(cs => {
        let skill = cs[1];        
        //map to extract only the customer id
        let customersAvailable = customers
            .filter(customer => customer[1] <= skill)
            .map(x => x[0]);
        //convert to set because i've wrote it's fast
        let customerAvSet = new Set(customersAvailable);
        //include on result list
        distribution.push([cs[0], customersAvailable.length]);
        //remove customers already assigned
        customers = customers.filter(([cs]) => !customerAvSet.has(cs));
    });
    //sort to first position be hightest score    
    distribution.sort((a, b) => b[1] - a[1]);

    //return operator
    return distribution[0][0];    
}

输入示例:

  • operators = [[1, 60], [3, 90]];
  • customers = [[1, 30], [1, 40], [1, 60], [1, 70]];

输出应为1。

主要规则:不能获得最高的操作技能并全力以赴。我需要在操作员之间保持平衡-我需要从较低的技能过渡到较高的技能。

关于如何优化它的任何提示?

谢谢。

3 个答案:

答案 0 :(得分:1)

此功能应按O(c*o)的顺序运行,其中c是客户数,o是操作员数。

  var o = [[1, 60], [3, 90]];
  var c = [[1, 30], [1, 40], [1, 60], [1, 70]];

  function countEmployersByMoodAtt(operatos, customers) {
  var cInt = [];
  var gInt = {};
  var i, j;
  var opIndex;

  for (i = 0; i < customers.length; i++) {
    // find lowest possible operator to interact with
    opIndex = null;
    for (j = operatos.length - 1; j >= 0; j--) {
      if (operatos[j][1] < customers[i][1]) {
        // can't interact. continue to next operator
        continue;
      }

      if (opIndex !== null) {
        if (operatos[j][1] < operatos[opIndex][1]) {
          opIndex = j;
        }
      } else {
        opIndex = j;
      }
    }

    if (opIndex === null) {
      cInt.push(null);
    } else {
      cInt.push(operatos[opIndex][0]);
    }
  }


  for (i = 0; i < cInt.length; i++) {
    if (gInt[cInt[i]] === undefined) {
      gInt[cInt[i]] = 0;
    }

    gInt[cInt[i]] += 1;
  }

  var maxId = null, maxOp = 0;
  var keys = Object.keys(gInt);

  for (i = 0; i < keys.length; i++) {
    if (gInt[keys[i]] > maxOp) {
      maxId = keys[i];
      maxOp = gInt[keys[i]];
    }
  }

  return maxId;
}

console.log(countEmployersByMoodAtt(o, c));

基准:

var o = [];
var c = [];

for (var k = 0; k < 10000; k++) {
  o.push([k + 1, Math.floor(Math.random() * 1000000)]);
  c.push([k + 1, Math.floor(Math.random() * 1000000)]);
}

function myCountEmployersByMoodAtt(operatos, customers) {
  var cInt = [];
  var gInt = {};
  var i, j;
  var opIndex;

  for (i = 0; i < customers.length; i++) {
    // find lowest possible operator to interact with
    opIndex = null;
    for (j = operatos.length - 1; j >= 0; j--) {
      if (operatos[j][1] < customers[i][1]) {
        // can't interact. continue to next operator
        continue;
      }

      if (opIndex !== null) {
        if (operatos[j][1] < operatos[opIndex][1]) {
          opIndex = j;
        }
      } else {
        opIndex = j;
      }
    }

    if (opIndex === null) {
      cInt.push(null);
    } else {
      cInt.push(operatos[opIndex][0]);
    }
  }


  for (i = 0; i < cInt.length; i++) {
    if (gInt[cInt[i]] === undefined) {
      gInt[cInt[i]] = 0;
    }

    gInt[cInt[i]] += 1;
  }

  var maxId = null, maxOp = 0;
  var keys = Object.keys(gInt);

  for (i = 0; i < keys.length; i++) {
    if (gInt[keys[i]] > maxOp) {
      maxId = keys[i];
      maxOp = gInt[keys[i]];
    }
  }

  return maxId;
}

function yourCountEmployersByMoodAtt(operatos, customers) {
  let distribution = [];
  //sort operators by skill so I can guarantee that big skills won't come first
  operatos.sort((a, b) => a[1] - b[1]);

  operatos.forEach(cs => {
    let skill = cs[1];
    //map to extract only the customer id
    let customersAvailable = customers
      .filter(customer => customer[1] <= skill)
      .map(x => x[0]);
    //convert to set because i've wrote it's fast
    let customerAvSet = new Set(customersAvailable);
    //include on result list
    distribution.push([cs[0], customersAvailable.length]);
    //remove customers already assigned
    customers = customers.filter(([cs]) => !customerAvSet.has(cs));
  });
  //sort to first position be hightest score
  distribution.sort((a, b) => b[1] - a[1]);

  //return operator
  return distribution[0][0];
}

var t0 = performance.now();
console.log('MyResult: ' + myCountEmployersByMoodAtt(o, c));
var t1 = performance.now();
console.log('Your result: ' + yourCountEmployersByMoodAtt(o, c));
var t2 = performance.now();
console.log('My time: ' + (t1 - t0));
console.log('Your time: ' + (t2 - t1));

答案 1 :(得分:1)

我建议使用具有降序排序和迭代客户技能的数组,该数组迭代计数器数组并检查心情m

如果counter小于技能,则增加计数,否则退出内循环。

var employers = [[1, 10], [2, 90]], customers = [[12, 5], [2, 70]], counter = employers.map(([, v]) => [v, 0]).sort(([a], [b]) => b - a); customers.forEach(([m]) => counter.every(a => m < a[0] && ++a[1])); console.log(counter);包含每个技能级别的计数。

    <select>
         <option value="" disabled="disabled" selected="selected">Please select a 
              developer position</option>
          <option value="1">Beginner</option>
          <option value="2">Expert</option>
     </select>

答案 2 :(得分:0)

好的,所以您的问题尚不清楚,但是通读代码就足够了。雇主可以以比他们的技能低的心情与客户互动,但是他们不能与另一个技能较低的员工也可以与之互动的客户互动。让我们解决这个问题。

对于一个过滤器来说,过滤,将结果复制到集合中,然后运行另一个过滤器以过滤掉刚刚过滤的所有内容几乎没有意义。听起来像是一团糟,对吗?它是。

相反,只需要最初与所有客户一起创建集合即可。然后运行forEach,并从技能最低的工作人员可以服务的客户集中删除客户,为您为此服务的每个客户增加一个计数器。您实际上并未随分发一起发送客户ID,因此完全保留客户ID毫无意义。

算法将如下所示: 根据技能和情绪对员工和客户进行排序。 创建一个计数器变量。 遍历客户。 对于每个客户,如果他们的心情<当前员工的技能,请增加计数器。 如果不是,请将计数与当前员工ID一起存储在分配中。然后转到下一个员工ID。

重复。实际上没有机会使用一套。我不认为他们已下令。不过,这可以很好地工作,并且您可以在排序后一次通过。

function countEmployersByMoodAtt(operators, customers) {
  console.log("Sorting operators.");
  operators.sort((a, b) => a[1] - b[1]);
  console.log("Sorting customers");
  customers.sort((a, b) => a[1] - b[1]);
  console.log("Starting processing.");

  let distribution = [];
  let opIndex = 0;
  let customersServed = 0;
  let bestEmployeeID;
  let mostServed = -1;
  let skill = operators[opIndex][1];

  for (let i = 0; i < customers.length; ++i) {
    let mood = customers[i][1];
    if (mood < skill) 
      ++customersServed;
    else {
      // check if new record.
      if (customersServed > mostServed) {
        mostServed = customersServed;
        bestEmployeeID = operators[opIndex][0];
        customersServed = 1; // this will count toward the employee found in while() loop.
      }
      // find next qualified employee.
      while (mood > skill && ++opIndex < operators.length) {
        skill = operators[opIndex][1];
      }
      // no employees can serve customer.
      if (opIndex >= operators.length) {
        console.log("No employees skilled enough for remaining customers.")
        return [bestEmployeeID, mostServed];
      }
    }
  }
  // need to do this one more time for the last set of customers. 
  // because 'else' case won't run if customer is served adequately.
  // and if a new employee is selected for the last customer, bestEmployee won't be set.
  if (customersServed > mostServed) {
    mostServed = customersServed;
    bestEmployeeID = operators[opIndex[0]];
  }
  return [bestEmployeeID, mostServed];
}